Home

Published

- 4 min read

The Unexpected Depth of toUppercase

img of The Unexpected Depth of toUppercase

Original Challenge : https://www.codewars.com/kata/57a0556c7cb1f31ab3000ad7

This appears to be a rather straightforward challenge. It serves as a gentle reminder that even a seemingly simple problem can lead to the discovery of unexpected things.

Write a function which converts the input string to uppercase.

Test Cases - “hello world”

CodeWars provides test cases, but I prefer to write my own to ensure I understand the problem correctly and practice writing tests.

describe("Uppercase Function", () => {
  it("should convert lowercase letters to uppercase", () => {
    expect(toUpperCase("hello world")).toBe("HELLO WORLD");
  });

  it("should handle empty string", () => {
    expect(toUpperCase("")).toBe("");
  });

  it("should handle strings with no lowercase letters", () => {
    expect(toUpperCase("HELLO WORLD")).toBe("HELLO WORLD");
  });

  it("should handle strings with mixed characters", () => {
    expect(toUpperCase("hello world! 123")).toBe("HELLO WORLD! 123");
  });

  it("should be able to handle german scharfes S", () => {
    expect(toUpperCase("straße")).toBe("STRASSE");
  });
});

Obvious Solution

Luckily JavaScript already provides exactly this function. toUpperCase documentation

export function toUpperCase(str: string): string {
	return str.toUpperCase();
}

Well that was a little anti-climatic? Just call a built-in function? We are here to exercise. Let’s just assume we do not have this function available - what would we do now?

The Hard Way

To make the string entirely uppercase we would have to do a couple of steps:

  1. Loop over every Character
  2. if it is lowercase return Uppercase
  3. else return the string
  4. combine the list of characters to a new string

But how do we figure out what is a ‘lowercase’ character? - We will probably have to look it up in a table.
So we write a function like this:

export function isLowerCase(char: string): boolean {
  const lowerCaseChars= ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
  return lowerCaseChars.includes(char);
}

However that would be incredibly inefficient, because for each time we call the function we would need to loop over the entire array. Also we would need a second array with the uppercase chars to then retrieve the corresponding value.


There is a better way, because every character in a string we can look up its ‘ascii’-code. Essentially converting the string into a number.

If we look at the Ascii Code Table we can see that the

  • “uppercase A” equals 65 and the “lowercase A” equals 97”
  • “uppercase Z” equals “90” and the “lowercase Z” equals 122”

So now we know that in the range of 97-122 all of the lowercase characters are and at the same time the range of the uppercase characters are 65-97. To covert a character you now have to subtract -32.

Ascii code solution

export function toUpperCaseByChar(str: string): string {
  let result = "";
  for (let i = 0; i < str.length; i++) {
    let asciiCode = str.charCodeAt(i);
    if (asciiCode >= 97 && asciiCode <= 122) {
      // a-z
      asciiCode -= 32;
    }
    const upperChar = String.fromCharCode(asciiCode);
    result += upperChar;
  }
  return result;
}```

# One Failing Test - 'scharfes S'
There is a character in German called "scharfes s" (Latin small letter sharp s - ess-zed) it looks like this `ß` (Ascii code 223) and by definition it is a lowercase character - and is corresponding uppercase is `SS`.

Essentially we will have to handle this as a special case:
```ts
export function toUpperCase(str: string): string {
  let result = "";
  for (let i = 0; i < str.length; i++) {
    let asciiCode = str.charCodeAt(i);
    if (asciiCode === 223) {
      // ß to SS
      result += "SS";
      continue;
    }
    if (asciiCode >= 97 && asciiCode <= 122) {
      // a-z
      asciiCode -= 32;
    }
    const upperChar = String.fromCharCode(asciiCode);
    result += upperChar;
  }
  return result;
}

Conclusion

While I was then fixing this last special case, when I was looking through the ASCII Table to find the scharfes S, I noticed there are even more international languages with lowercase characters like ASCII Code 192 - Latin capital letter A with grave.

So even now this is not a full implementation of the equivalent built-in toUpperCase-function. But I’ll stop here because the point I wanted to make is that even when we are dealing with rather straightforward and simple questions, there is a lot to explore and learn about how to write code. What are the tradeoffs, what tools are available to solve the problem?

The other thing that you can learn is that you probably should use and be grateful for built-in functions. The developers that created that function put a lot of care and thought into it on how these work, and they usually take care of a lot of edge cases that you did not think about.

Image: Created on 2025-12-03 by Gemini / Nano Banana, using the article as a prompt.