Problem overview
The method convertToHackerSpeak(input) receives a string and returns a coded copy of it ("h4ck3r 5p34k"). Five lowercase letters are swapped for look-alike digits, and everything else stays as it is:
| Letter | Becomes |
|---|---|
a | 4 |
e | 3 |
i | 1 |
o | 0 |
s | 5 |
For "javascript is cool" the result is "j4v45cr1pt 15 c00l". Letters outside the table, spaces and punctuation are copied unchanged, and "programming is fun" becomes "pr0gr4mm1ng 15 fun".
Approach
A JavaScript string cannot be edited in place, so assigning to input[4] does nothing. The way around it is to build a new string while reading the old one. Start with an empty result and look at the input one character at a time. For each character, append its replacement if it has one, and the character itself if not. When the last character is handled, the result is complete.
Every character is looked at once and appended once, so the work grows in step with the length of the input.
Here is the idea on the word "cool". The result starts as "". The character c matches none of the five letters, so it is appended unchanged and the result is "c". Each o matches the fourth condition and appends 0, giving "c0" and then "c00". Finally l is appended as it is, and the method returns "c00l".
If uppercase letters should be coded too, compare against the lowercase form of the character, as in c.toLowerCase() == 'a', while still appending the digit. The task names lowercase letters only, so the solution below compares c directly.
Step by step
- Create
solutionas an empty string withlet. It has to beletand notconst, because+=reassigns it each time it grows. - Loop over the characters of
inputwithfor (let c of input). Afor...ofloop on a string gives the characters one by one, in order. (for...inwould give the indexes instead.) - Handle
'a'first. Ifcequals'a', append'4'. JavaScript has no separate character type, socis a string of length 1, and comparing it with'a'is an ordinary string comparison. - Chain an
else iffor'e', appending'3'. Anelse ifis tested only when every earlier condition was false. - Chain one for
'i', appending'1'. - Chain one for
'o', appending'0'. - Chain one for
's', appending'5'. Only one branch of the chain runs for each character. - Finish with a plain
else, appendingcunchanged. Spaces, punctuation, digits and all other letters take this path. - Return
solutionafter the loop, once every character has been processed.
The solution in JavaScript
class Solution {
convertToHackerSpeak(input) {
let solution = "";
for (let c of input) {
if (c == 'a') {
solution += '4';
} else if (c == 'e') {
solution += '3';
} else if (c == 'i') {
solution += '1';
} else if (c == 'o') {
solution += '0';
} else if (c == 's') {
solution += '5';
} else {
solution += c;
}
}
return solution;
}
}
Details worth knowing:
- Each
+=makes a new string. Strings are immutable, sosolution += '4'builds a new string and stores it back in the variable. The originalinputis never changed. - Quote style.
'a'and"a"are the same string. The lesson uses single quotes for the characters and double quotes for the empty string. ==versus===. Both sides are strings, so==works here.===is the safer habit in general.- Case matters. Only lowercase letters are replaced.
"AEIOS"stays"AEIOS", and"AEIOS aeios"becomes"AEIOS 43105". for...ofreads code points, not UTF-16 units, so characters such as an emoji pass through as single items and are appended whole.
Other ways to write it
The chain of conditions works for five letters, but a lookup table is shorter and easier to extend. An object maps each letter to its digit, and the nullish operator ?? falls back to the original character when there is no entry:
const digits = { a: '4', e: '3', i: '1', o: '0', s: '5' };
function toHackerSpeak(input) {
return [...input].map(c => digits[c] ?? c).join('');
}
console.log(toHackerSpeak("become a coder")); // b3c0m3 4 c0d3r
Reading a missing key of an object gives undefined, and undefined ?? c is c. This works for single characters. A regular expression with a callback is shorter still: input.replace(/[aeios]/g, c => digits[c]). Chaining replaceAll five times also works, but the loop in the lesson is the clearest way to see what happens to each character.
Complexity
Time: O(n), where n is the length of input. The loop runs once per character and each iteration does a fixed number of comparisons.
Space: O(n). The result string ends up as long as the input. Because strings cannot be changed, a copy is needed anyway.
Edge cases and common mistakes
- Empty string. The loop never runs and the method returns
"". - Nothing to replace.
"xyz 123 !?"comes back unchanged. - Uppercase letters.
"Sea"becomes"S34", because the uppercaseSis not replaced. - Trying to edit the input. Writing
input[i] = '4'does not change the string. Build a new one. - Using
ifinstead ofelse if. With separateifstatements, the finalelsewould also run for the letters that were just replaced, and both the digit and the letter would be appended. - Declaring
solutionwithconst. The first+=throwsTypeError: Assignment to constant variable.
Testing
"javascript is cool"gives"j4v45cr1pt 15 c00l"."programming is fun"gives"pr0gr4mm1ng 15 fun"."become a coder"gives"b3c0m3 4 c0d3r".""gives""."AEIOS aeios"gives"AEIOS 43105".
