--- id: 646d39c156fe94b7482c3ab6 title: Step 61 challengeType: 0 dashedName: step-61 --- # --description-- Declare a variable `cellRegex` to match cell references. It should match a letter from `A` to `J`, followed by a digit from `1` to `9`, and an optional digit from `0` to `9`. Make the regular expression case-insensitive and global. # --hints-- You should declare a `cellRegex` variable. ```js assert.match(code, /const\s+evalFormula\s*=\s*\(\s*x\s*,\s*cells\s*\)\s*=>\s*{\s*const\s+idToText\s*=\s*(\(\s*id\s*\)|id)\s*=>\s*cells\.find\(\s*(\(\s*cell\s*\)|cell)\s*=>\s*(?:cell\.id\s*===\s*id|id\s*===\s*cell\.id)\s*\)\.value\s*;?\s*const\s+rangeRegex\s*=\s*\/\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\):\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\)\/(gi|ig)\s*;?\s*const\s+rangeFromString\s*=\s*\(\s*num1\s*,\s*num2\s*\)\s*=>\s*range\(\s*parseInt\(\s*num1\s*\)\s*,\s*parseInt\(\s*num2\s*\)\s*\)\s*;?\s*const\s+elemValue\s*=\s*(\(\s*num\s*\)|num)\s*=>\s*(\(\s*character\s*\)|character)\s*=>\s*idToText\(\s*character\s*\+\s*num\s*\)\s*;?\s*const\s+addCharacters\s*=\s*(\(\s*character1\s*\)|character1)\s*=>\s*(\(\s*character2\s*\)|character2)\s*=>\s*(\(\s*num\s*\)|num)\s*=>\s*charRange\(\s*character1\s*,\s*character2\s*\)\.map\(\s*elemValue\(\s*num\s*\)\s*\)\s*;?\s*const\s+rangeExpanded\s*=\s*x\.replace\(\s*rangeRegex\s*,\s*\(\s*_match\s*,\s*char1\s*,\s*num1\s*,\s*char2\s*,\s*num2\s*\)\s*=>\s*rangeFromString\(\s*num1\s*,\s*num2\s*\)\.map\(\s*addCharacters\s*\(\s*char1\s*\)\(\s*char2\s*\)\s*\)\s*\)\s*;?\s*(?:var|let|const)\s+cellRegex/); ``` You should use `const` to declare your `cellRegex` variable. ```js assert.match(code, /const\s+evalFormula\s*=\s*\(\s*x\s*,\s*cells\s*\)\s*=>\s*{\s*const\s+idToText\s*=\s*(\(\s*id\s*\)|id)\s*=>\s*cells\.find\(\s*(\(\s*cell\s*\)|cell)\s*=>\s*(?:cell\.id\s*===\s*id|id\s*===\s*cell\.id)\s*\)\.value\s*;?\s*const\s+rangeRegex\s*=\s*\/\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\):\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\)\/(gi|ig)\s*;?\s*const\s+rangeFromString\s*=\s*\(\s*num1\s*,\s*num2\s*\)\s*=>\s*range\(\s*parseInt\(\s*num1\s*\)\s*,\s*parseInt\(\s*num2\s*\)\s*\)\s*;?\s*const\s+elemValue\s*=\s*(\(\s*num\s*\)|num)\s*=>\s*(\(\s*character\s*\)|character)\s*=>\s*idToText\(\s*character\s*\+\s*num\s*\)\s*;?\s*const\s+addCharacters\s*=\s*(\(\s*character1\s*\)|character1)\s*=>\s*(\(\s*character2\s*\)|character2)\s*=>\s*(\(\s*num\s*\)|num)\s*=>\s*charRange\(\s*character1\s*,\s*character2\s*\)\.map\(\s*elemValue\(\s*num\s*\)\s*\)\s*;?\s*const\s+rangeExpanded\s*=\s*x\.replace\(\s*rangeRegex\s*,\s*\(\s*_match\s*,\s*char1\s*,\s*num1\s*,\s*char2\s*,\s*num2\s*\)\s*=>\s*rangeFromString\(\s*num1\s*,\s*num2\s*\)\.map\(\s*addCharacters\s*\(\s*char1\s*\)\(\s*char2\s*\)\s*\)\s*\)\s*;?\s*const\s+cellRegex/); ``` You should assign a regular expression to your `cellRegex` variable. ```js assert.match(code, /const\s+evalFormula\s*=\s*\(\s*x\s*,\s*cells\s*\)\s*=>\s*{\s*const\s+idToText\s*=\s*(\(\s*id\s*\)|id)\s*=>\s*cells\.find\(\s*(\(\s*cell\s*\)|cell)\s*=>\s*(?:cell\.id\s*===\s*id|id\s*===\s*cell\.id)\s*\)\.value\s*;?\s*const\s+rangeRegex\s*=\s*\/\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\):\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\)\/(gi|ig)\s*;?\s*const\s+rangeFromString\s*=\s*\(\s*num1\s*,\s*num2\s*\)\s*=>\s*range\(\s*parseInt\(\s*num1\s*\)\s*,\s*parseInt\(\s*num2\s*\)\s*\)\s*;?\s*const\s+elemValue\s*=\s*(\(\s*num\s*\)|num)\s*=>\s*(\(\s*character\s*\)|character)\s*=>\s*idToText\(\s*character\s*\+\s*num\s*\)\s*;?\s*const\s+addCharacters\s*=\s*(\(\s*character1\s*\)|character1)\s*=>\s*(\(\s*character2\s*\)|character2)\s*=>\s*(\(\s*num\s*\)|num)\s*=>\s*charRange\(\s*character1\s*,\s*character2\s*\)\.map\(\s*elemValue\(\s*num\s*\)\s*\)\s*;?\s*const\s+rangeExpanded\s*=\s*x\.replace\(\s*rangeRegex\s*,\s*\(\s*_match\s*,\s*char1\s*,\s*num1\s*,\s*char2\s*,\s*num2\s*\)\s*=>\s*rangeFromString\(\s*num1\s*,\s*num2\s*\)\.map\(\s*addCharacters\s*\(\s*char1\s*\)\(\s*char2\s*\)\s*\)\s*\)\s*;?\s*const\s+cellRegex\s*=\s*\//); ``` Your regular expression should use a character class to match the characters from `A` to `J`. ```js assert.match(code, /const\s+evalFormula\s*=\s*\(\s*x\s*,\s*cells\s*\)\s*=>\s*{\s*const\s+idToText\s*=\s*(\(\s*id\s*\)|id)\s*=>\s*cells\.find\(\s*(\(\s*cell\s*\)|cell)\s*=>\s*(?:cell\.id\s*===\s*id|id\s*===\s*cell\.id)\s*\)\.value\s*;?\s*const\s+rangeRegex\s*=\s*\/\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\):\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\)\/(gi|ig)\s*;?\s*const\s+rangeFromString\s*=\s*\(\s*num1\s*,\s*num2\s*\)\s*=>\s*range\(\s*parseInt\(\s*num1\s*\)\s*,\s*parseInt\(\s*num2\s*\)\s*\)\s*;?\s*const\s+elemValue\s*=\s*(\(\s*num\s*\)|num)\s*=>\s*(\(\s*character\s*\)|character)\s*=>\s*idToText\(\s*character\s*\+\s*num\s*\)\s*;?\s*const\s+addCharacters\s*=\s*(\(\s*character1\s*\)|character1)\s*=>\s*(\(\s*character2\s*\)|character2)\s*=>\s*(\(\s*num\s*\)|num)\s*=>\s*charRange\(\s*character1\s*,\s*character2\s*\)\.map\(\s*elemValue\(\s*num\s*\)\s*\)\s*;?\s*const\s+rangeExpanded\s*=\s*x\.replace\(\s*rangeRegex\s*,\s*\(\s*_match\s*,\s*char1\s*,\s*num1\s*,\s*char2\s*,\s*num2\s*\)\s*=>\s*rangeFromString\(\s*num1\s*,\s*num2\s*\)\.map\(\s*addCharacters\s*\(\s*char1\s*\)\(\s*char2\s*\)\s*\)\s*\)\s*;?\s*const\s+cellRegex\s*=\s*\/\[A-J\]/); ``` Your regular expression should use a character class to match the digits from `1` to `9`. ```js assert.match(code, /const\s+evalFormula\s*=\s*\(\s*x\s*,\s*cells\s*\)\s*=>\s*{\s*const\s+idToText\s*=\s*(\(\s*id\s*\)|id)\s*=>\s*cells\.find\(\s*(\(\s*cell\s*\)|cell)\s*=>\s*(?:cell\.id\s*===\s*id|id\s*===\s*cell\.id)\s*\)\.value\s*;?\s*const\s+rangeRegex\s*=\s*\/\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\):\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\)\/(gi|ig)\s*;?\s*const\s+rangeFromString\s*=\s*\(\s*num1\s*,\s*num2\s*\)\s*=>\s*range\(\s*parseInt\(\s*num1\s*\)\s*,\s*parseInt\(\s*num2\s*\)\s*\)\s*;?\s*const\s+elemValue\s*=\s*(\(\s*num\s*\)|num)\s*=>\s*(\(\s*character\s*\)|character)\s*=>\s*idToText\(\s*character\s*\+\s*num\s*\)\s*;?\s*const\s+addCharacters\s*=\s*(\(\s*character1\s*\)|character1)\s*=>\s*(\(\s*character2\s*\)|character2)\s*=>\s*(\(\s*num\s*\)|num)\s*=>\s*charRange\(\s*character1\s*,\s*character2\s*\)\.map\(\s*elemValue\(\s*num\s*\)\s*\)\s*;?\s*const\s+rangeExpanded\s*=\s*x\.replace\(\s*rangeRegex\s*,\s*\(\s*_match\s*,\s*char1\s*,\s*num1\s*,\s*char2\s*,\s*num2\s*\)\s*=>\s*rangeFromString\(\s*num1\s*,\s*num2\s*\)\.map\(\s*addCharacters\s*\(\s*char1\s*\)\(\s*char2\s*\)\s*\)\s*\)\s*;?\s*const\s+cellRegex\s*=\s*\/\[A-J\]\[1-9\]/); ``` Your regular expression should use a character class to match the digits from `0` to `9`. ```js assert.match(code, /const\s+evalFormula\s*=\s*\(\s*x\s*,\s*cells\s*\)\s*=>\s*{\s*const\s+idToText\s*=\s*(\(\s*id\s*\)|id)\s*=>\s*cells\.find\(\s*(\(\s*cell\s*\)|cell)\s*=>\s*(?:cell\.id\s*===\s*id|id\s*===\s*cell\.id)\s*\)\.value\s*;?\s*const\s+rangeRegex\s*=\s*\/\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\):\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\)\/(gi|ig)\s*;?\s*const\s+rangeFromString\s*=\s*\(\s*num1\s*,\s*num2\s*\)\s*=>\s*range\(\s*parseInt\(\s*num1\s*\)\s*,\s*parseInt\(\s*num2\s*\)\s*\)\s*;?\s*const\s+elemValue\s*=\s*(\(\s*num\s*\)|num)\s*=>\s*(\(\s*character\s*\)|character)\s*=>\s*idToText\(\s*character\s*\+\s*num\s*\)\s*;?\s*const\s+addCharacters\s*=\s*(\(\s*character1\s*\)|character1)\s*=>\s*(\(\s*character2\s*\)|character2)\s*=>\s*(\(\s*num\s*\)|num)\s*=>\s*charRange\(\s*character1\s*,\s*character2\s*\)\.map\(\s*elemValue\(\s*num\s*\)\s*\)\s*;?\s*const\s+rangeExpanded\s*=\s*x\.replace\(\s*rangeRegex\s*,\s*\(\s*_match\s*,\s*char1\s*,\s*num1\s*,\s*char2\s*,\s*num2\s*\)\s*=>\s*rangeFromString\(\s*num1\s*,\s*num2\s*\)\.map\(\s*addCharacters\s*\(\s*char1\s*\)\(\s*char2\s*\)\s*\)\s*\)\s*;?\s*const\s+cellRegex\s*=\s*\/\[A-J\]\[1-9\]\[0-9\]/); ``` Your third character class should be optional. ```js assert.match(code, /const\s+evalFormula\s*=\s*\(\s*x\s*,\s*cells\s*\)\s*=>\s*{\s*const\s+idToText\s*=\s*(\(\s*id\s*\)|id)\s*=>\s*cells\.find\(\s*(\(\s*cell\s*\)|cell)\s*=>\s*(?:cell\.id\s*===\s*id|id\s*===\s*cell\.id)\s*\)\.value\s*;?\s*const\s+rangeRegex\s*=\s*\/\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\):\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\)\/(gi|ig)\s*;?\s*const\s+rangeFromString\s*=\s*\(\s*num1\s*,\s*num2\s*\)\s*=>\s*range\(\s*parseInt\(\s*num1\s*\)\s*,\s*parseInt\(\s*num2\s*\)\s*\)\s*;?\s*const\s+elemValue\s*=\s*(\(\s*num\s*\)|num)\s*=>\s*(\(\s*character\s*\)|character)\s*=>\s*idToText\(\s*character\s*\+\s*num\s*\)\s*;?\s*const\s+addCharacters\s*=\s*(\(\s*character1\s*\)|character1)\s*=>\s*(\(\s*character2\s*\)|character2)\s*=>\s*(\(\s*num\s*\)|num)\s*=>\s*charRange\(\s*character1\s*,\s*character2\s*\)\.map\(\s*elemValue\(\s*num\s*\)\s*\)\s*;?\s*const\s+rangeExpanded\s*=\s*x\.replace\(\s*rangeRegex\s*,\s*\(\s*_match\s*,\s*char1\s*,\s*num1\s*,\s*char2\s*,\s*num2\s*\)\s*=>\s*rangeFromString\(\s*num1\s*,\s*num2\s*\)\.map\(\s*addCharacters\s*\(\s*char1\s*\)\(\s*char2\s*\)\s*\)\s*\)\s*;?\s*const\s+cellRegex\s*=\s*\/\[A-J\]\[1-9\]\[0-9\]\?/); ``` Your regular expression should be case-insensitive and global. ```js assert.match(code, /const\s+evalFormula\s*=\s*\(\s*x\s*,\s*cells\s*\)\s*=>\s*{\s*const\s+idToText\s*=\s*(\(\s*id\s*\)|id)\s*=>\s*cells\.find\(\s*(\(\s*cell\s*\)|cell)\s*=>\s*(?:cell\.id\s*===\s*id|id\s*===\s*cell\.id)\s*\)\.value\s*;?\s*const\s+rangeRegex\s*=\s*\/\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\):\(\[A-J\]\)\(\[1-9\]\[0-9\]\?\)\/(gi|ig)\s*;?\s*const\s+rangeFromString\s*=\s*\(\s*num1\s*,\s*num2\s*\)\s*=>\s*range\(\s*parseInt\(\s*num1\s*\)\s*,\s*parseInt\(\s*num2\s*\)\s*\)\s*;?\s*const\s+elemValue\s*=\s*(\(\s*num\s*\)|num)\s*=>\s*(\(\s*character\s*\)|character)\s*=>\s*idToText\(\s*character\s*\+\s*num\s*\)\s*;?\s*const\s+addCharacters\s*=\s*(\(\s*character1\s*\)|character1)\s*=>\s*(\(\s*character2\s*\)|character2)\s*=>\s*(\(\s*num\s*\)|num)\s*=>\s*charRange\(\s*character1\s*,\s*character2\s*\)\.map\(\s*elemValue\(\s*num\s*\)\s*\)\s*;?\s*const\s+rangeExpanded\s*=\s*x\.replace\(\s*rangeRegex\s*,\s*\(\s*_match\s*,\s*char1\s*,\s*num1\s*,\s*char2\s*,\s*num2\s*\)\s*=>\s*rangeFromString\(\s*num1\s*,\s*num2\s*\)\.map\(\s*addCharacters\s*\(\s*char1\s*\)\(\s*char2\s*\)\s*\)\s*\)\s*;?\s*const\s+cellRegex\s*=\s*\/\[A-J\]\[1-9\]\[0-9\]\?\/(gi|ig)/); ``` # --seed-- ## --seed-contents-- ```html Functional Programming Spreadsheet
``` ```css #container { display: grid; grid-template-columns: 50px repeat(10, 200px); grid-template-rows: repeat(11, 30px); } .label { background-color: lightgray; text-align: center; vertical-align: middle; line-height: 30px; } ``` ```js const isEven = num => num % 2 === 0; const sum = nums => nums.reduce((acc, el) => acc + el, 0); const average = nums => sum(nums) / nums.length; const median = nums => { const sorted = nums.slice().sort((a, b) => a - b); const length = sorted.length; const middle = length / 2 - 1; return isEven(length) ? average([sorted[middle], sorted[middle + 1]]) : sorted[Math.ceil(middle)]; } const spreadsheetFunctions = { sum, average, median } const range = (start, end) => Array(end - start + 1).fill(start).map((element, index) => element + index); const charRange = (start, end) => range(start.charCodeAt(0), end.charCodeAt(0)).map(code => String.fromCharCode(code)); --fcc-editable-region-- const evalFormula = (x, cells) => { const idToText = id => cells.find(cell => cell.id === id).value; const rangeRegex = /([A-J])([1-9][0-9]?):([A-J])([1-9][0-9]?)/gi; const rangeFromString = (num1, num2) => range(parseInt(num1), parseInt(num2)); const elemValue = num => character => idToText(character + num); const addCharacters = character1 => character2 => num => charRange(character1, character2).map(elemValue(num)); const rangeExpanded = x.replace(rangeRegex, (_match, char1, num1, char2, num2) => rangeFromString(num1, num2).map(addCharacters(char1)(char2))); } --fcc-editable-region-- window.onload = () => { const container = document.getElementById("container"); const createLabel = (name) => { const label = document.createElement("div"); label.className = "label"; label.textContent = name; container.appendChild(label); } const letters = charRange("A", "J"); letters.forEach(createLabel); range(1, 99).forEach(number => { createLabel(number); letters.forEach(letter => { const input = document.createElement("input"); input.type = "text"; input.id = letter + number; input.ariaLabel = letter + number; input.onchange = update; container.appendChild(input); }) }) } const update = event => { const element = event.target; const value = element.value.replace(/\s/g, ""); if (!value.includes(element.id) && value.startsWith('=')) { } } ```