Problem overview
The function convertToHackerSpeak receives a string and returns a coded copy of it. Every a becomes 4, every e becomes 3, every i becomes 1, every o becomes 0 and every s becomes 5. All other characters stay as they are.
For example, "javascript is cool" becomes "j4v45cr1pt 15 c00l", and "become a coder" becomes "b3c0m3 4 c0d3r". Only lowercase letters are replaced: an uppercase S or A is left untouched, because it is a different character from s or a.
Approach
Go strings are immutable, so you can't overwrite a character in place: there is no way to turn the fifth character of the input into a 4. The solution instead builds a new string. It starts with an empty one, walks through the input one character at a time, and appends either the replacement digit or the original character.
Each character needs a decision with five special cases and a default. A chain of if and else if branches expresses this directly: the first condition that is true decides, and the rest are skipped. The final else catches everything that is not one of the five letters.
Step by step
- Declare
solutionas an empty string with:=. The empty string literal makes the variable astring, and it will collect the output. - Loop over the input with
for ... range. Ranging over a string yields the byte position and the character of each step. The position isn't needed, so it is discarded with_, and the character is namedc. - Test for
'a'. Ifcis that letter, append"4". The letter is written in single quotes becausecis arune, Go's type for a single character, while the digit is written in double quotes because it is appended to a string. - Test for
'e'in anelse ifand append"3". - Test for
'i'in the nextelse ifand append"1". - Test for
'o'and append"0". - Test for
's'and append"5". - Handle everything else in a final
elseby appending the original character. Go won't add aruneto astringdirectly, so it is converted withstring(c)first. - Return
solutionafter the loop, once every character has been processed.
The solution in Go
func convertToHackerSpeak(input string) string {
solution := ""
for _, c := range 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 += string(c)
}
}
return solution
}
The Go details worth a closer look:
- Bytes versus runes. A string is a sequence of bytes. Indexing with
input[i]gives a single byte, whilerangedecodes the string into runes (Unicode code points). For the two-character string"hé",lenis 3 becauseétakes two bytes, andrangevisitshat position 0 andéat position 1. Looping withrangekeeps non-ASCII characters intact. - Single quotes and double quotes.
'a'is a rune literal, a number under the hood (97 fora), and"a"is a string. Comparing a rune with a string, as inc == "a", does not compile. string(c)on a rune. Converting a rune gives a one-character string. Converting an arbitraryintthis way is a common source of surprises, since it produces the character with that code and not the digits of the number, but for a rune it is exactly what you want.else ifplacement. Go requireselseon the same line as the closing brace of the previous block:} else if ... {. Starting a line withelseis a syntax error.- Strings can't be edited.
input[4] = '4'does not compile. Each+=creates a new string.
Complexity
Let n be the length of the input. The loop runs once per character, and the work per character is a few comparisons, so the logic is O(n) time and the result needs O(n) space.
There is a catch for very long inputs. Each solution += ... may copy the string built so far, so repeated appending can cost more than O(n) in total. For lesson-sized strings this does not matter. In code that handles large text, the usual tool is strings.Builder, which appends into a growing buffer: create it with var sb strings.Builder, call sb.WriteRune(c) for each character, and read the result with sb.String().
Edge cases and common mistakes
- Empty string. The loop never runs and the function returns
"". - Uppercase letters.
"Seas"becomes"S345". The capitalSis not replaced, since only lowercase letters are listed. - Characters that need no change. Spaces, digits, punctuation and letters such as
forureach the finalelseand are copied unchanged. - Forgetting the final
else. Without it, every unlisted character would be dropped from the result. - Using separate
ifstatements. With a chain of plainifs, the finalelsewould belong only to the lastif, and every letter that was already replaced would be copied as well.else ifkeeps the cases exclusive. - Appending
cwithout conversion.solution += cfails to compile because arunecan't be added to astring.
Testing
"javascript is cool"gives"j4v45cr1pt 15 c00l"."programming is fun"gives"pr0gr4mm1ng 15 fun"."become a coder"gives"b3c0m3 4 c0d3r"."Seas"gives"S345".""gives"".