Start learning free

LESSON 147 OF 415 · LOOPS & GLOBAL VARIABLES

Hacker Speak in Swift: Building a String Character by Character

Practice Read the full explanation

Given a string, write a function that returns a coded (h4ck3r 5p34k) version of the string.

In order to work properly, the function should replace all "a"s with 4, "e"s with 3, "i"s with 1, "o"s with 0, and "s"s with 5.

Example 1:

Input:  "javascript is cool"

Output: "j4v45cr1pt 15 c00l"

Example 2:

Input:  "programming is fun"

Output: "pr0gr4mm1ng 15 fun"

Example 3:

Input:  "become a coder"

Output: "b3c0m3 4 c0d3r"
Hints:

We have to iterate through every character of input, check for each scenario and treat it accordingly:
  • Is it an 'a'? If so, replace with '4'. Otherwise:
  • Is it an 'e'? If so, replace with '3'. Otherwise:
  • Is it an 'i'? If so, replace with '1'. Otherwise:
  • Is it an 'o'? If so, replace with '0'. Otherwise:
  • Is it an 's'? If so, replace with '5'. Otherwise, keep it as it is.
In many languages strings are immutable, so we don't change input in place. How does that affect us? How can we put this strategy into code?

In many languages strings are immutable, which means you cannot directly change a character of a string (for example, assigning '4' to the character at index 4 of input). So we create a new string where we will store the solution as we build it. How can we translate these two hints in code?

Let's create a new string named solution, initially empty, where we will push all the encoded characters of input. We will use a for loop and a character variable c to iterate through input and treat the scenarios inside the loop:
  • Start with solution as an empty string.
  • For each character c of input: if c is 'a', append '4' to solution; if it is 'e', append '3'; if 'i', append '1'; if 'o', append '0'; if 's', append '5'; otherwise append c itself.
  • After the loop, return solution.


We have a for loop that performs exactly n iterations (n is the length of input), thus the Time Complexity is O(n).
The extra space we use is the extra string solution. Its length will be n in the end, thus the Extra Space used is also O(n).
(This assumes appending a character takes constant time. In languages where += on an immutable string copies the whole string each time, the running time can be closer to O(n2).)
STEP 1 OF 9
    Ctrl + Enter to check

    SWIFT · LOOPS & GLOBAL VARIABLES

    Hacker Speak in Swift, explained

    Problem overview

    The method convertToHackerSpeak receives a string and returns a coded copy in which a becomes 4, e becomes 3, i becomes 1, o becomes 0 and s becomes 5. Every other character stays as it is.

    For "javascript is cool" the result is "j4v45cr1pt 15 c00l". For "become a coder" it is "b3c0m3 4 c0d3r".

    Approach: build a new string

    A Swift String is a value that you can't patch one character at a time by position. Instead, create an empty result and go through the input character by character. For each one, decide what to append: the digit for a special letter, or the character itself. This is one pass over the input.

    Only lowercase letters are replaced. An uppercase A is a different character from a, so it passes through unchanged.

    A tempting alternative is a chain of replacement calls, one per letter. That reads the whole string five times and is easy to get wrong when one replacement produces text another one matches. Here the replacement digits are never re-examined, because each input character is looked at once. A dictionary from letter to digit would shorten the code, but the explicit chain keeps every rule visible and practises else if.

    Trace "a cat". The characters are a, a space, c, a and t. The first a matches the first branch and appends 4. The space matches none of the five tests and reaches the else, which copies it. c is copied, the second a becomes 4, and t is copied. The result is "4 c4t".

    The order of the tests doesn't change the result, since each test looks at a different letter and at most one of them can be true for a given character. The order only decides how many comparisons a character costs before it is handled.

    Step by step

    1. Create the result. var solution = "" is a mutable empty string, since it grows.
    2. Loop over the characters. for c in input gives each element as a Character.
    3. Test for "a". If c == "a", append "4".
    4. Chain the other letters with else if: "e" gives "3", "i" gives "1", "o" gives "0", "s" gives "5". Only one branch runs for each character.
    5. Default case. In the final else, append the character unchanged with String(c).
    6. Return solution after the loop.

    The solution in Swift

    class Solution {
        func convertToHackerSpeak(_ input: String) -> String {
            var solution = ""
            for c in 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
        }
    }
    

    Swift details worth knowing:

    • Character versus String. Looping over a string yields Character values. Swift has no single-quote literals: "a" is written with double quotes and becomes a Character when compared with c, or a String when added to solution. The context decides.
    • Why String(c). The operator += on a String needs another String. Writing solution += c with a Character does not compile: Swift cannot convert a value of type Character to the expected argument type String.
    • No indexing by integer. input[4] is not allowed on a String, because characters have different sizes in memory. Looping with for avoids the problem.
    • Unicode. A Character is one user-perceived character, so letters with accents or emoji are treated as single units and pass through unchanged.
    • Value semantics. solution is its own string. Changing it never affects input.

    A shorter version with a dictionary

    Once the chain works, the same rules fit in a lookup table. A dictionary subscript returns an optional, which is nil for a missing key, and the ?? operator supplies a fallback for that case:

    let codes: [Character: String] = ["a": "4", "e": "3", "i": "1", "o": "0", "s": "5"]
    
    func convert(_ input: String) -> String {
        var solution = ""
        for c in input {
            solution += codes[c] ?? String(c)
        }
        return solution
    }
    

    For "javascript is cool" this returns "j4v45cr1pt 15 c00l", the same as the lesson's version. Accented letters such as the two é in "été" are different characters from e and stay unchanged, and an emoji passes through as a single character: "a🙂s" becomes "4🙂5". Adding a new rule is one more entry in the table. For the lesson itself, write the explicit chain of comparisons the steps describe.

    Complexity

    Time: O(n), where n is the length of input. Each character is examined once, and at most five comparisons run for it, which is constant work.

    Space: O(n). The result string ends up with exactly as many characters as the input.

    Edge cases and common mistakes

    • Empty input. The loop does nothing and the function returns "".
    • Uppercase letters. "Alice" becomes "Al1c3": the capital A is not replaced.
    • Spaces and punctuation. They reach the final else and are copied.
    • Using separate if statements. A chain of plain ifs with an else only on the last one would copy special letters as well, because that else would pair with the last if alone.
    • Adding the wrong digit. The mapping is easy to mix up: the digits are 4, 3, 1, 0 and 5 for a, e, i, o and s. Check each branch against the table in the task, and note that 2, 6, 7, 8 and 9 never appear.
    • Forgetting the default. Without the final else, letters like j and v would vanish.

    Testing

    Try these inputs in the editor above, and compare each result with the expected output.

    • "javascript is cool" gives "j4v45cr1pt 15 c00l".
    • "become a coder" gives "b3c0m3 4 c0d3r".
    • "Alice" gives "Al1c3".
    • "" gives "".
    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free