Strings and String Manipulation in Javascript

In our previous classes we've touched on strings as a way of taking input from the user and showing output to them. However, we haven't looked at strings much in themselves.

This is because strings are a bit more complex than our other types of variable. Unfortunately, they're also really common! This is because strings can be used to represent almost any other value provided there's an agreed-on way to interpret them. You'll find strings being used for data types as diverse as:

  • Numbers
  • Dates
  • Objects
  • Web requests

The best way to think of strings is as lists of characters, and in fact in low-level languages like C this is how they're represented.

There are many ways of manipulating strings, and we'll cover some of them in this class. Probably the most common thing we want to do with a string is find out how long it is:

let myString = "Hello!"
console.log(myString.length)

Because strings are a list of characters you can get a character at any position or index in the string (starting from 0) by using square brackets.

You can use this with a loop to look at or manipulate strings on a character-by-character basis.

let myString = "Hello world!"
console.log(myString[5])

// print the string character-by-character, iterating backwards
for (let i = myString.length - 1; i >= 0; i--) {
  console.log(myString[i])
}

Another common operation that we need to perform on strings is to concatenate them (join them together). Just like integers, this can be done with or without the assignment operator:

let hello = "Hello"
let world = "World!"
let helloWorld = hello + " " + world
console.log(helloWorld)
let digits = ""
for (let i = 0; i <= 9; i++) {
  digits += i.toString()
}
console.log(digits)

You can also compare strings with < and > in the same way as numbers, which will compare them alphabetically.

"a" < "b"
"dog" > "cat"

Not every character you might want in a string is easy to type on a keyboard or makes sense in a string. For example, what if you want to put the " character inside a string? """ will break your code.

To solve this problem, there are special escape codes for certain characters.

\n - new line`
\" 
\' - quote marks
\\ - backslash
\u - any unicode character by number

This can lead to "interesting" pieces of code that are a little bit challenging to read.

let myStr = "Hello \"world!\""
console.log(myStr)
let myStr = "\n\u2705\n\u2705\n\u2705"
console.log(myStr)

Exercise 1

  1. Write a program that takes a string and reverses it - e.g. if the user inputs "abcd" they should get back "dcba".
  2. A palindrome is a string which reads the same both forward and reversed. For example: madam, or eve. Write a piece of code that checks whether a string is a palindrome, returning true if so or false if not.

Some Helpful Functions

This represents only a small fraction of things that you can do with strings. For an exhaustive list you can check the MDN documentation here

toUpperCase() MAKES STRINGS UPPER CASE. toLowerCase() makes strings lower case.

let what = "What are you doing?"
let wtf = what.toUpperCase()

trim() removes whitespace from the start and end of a string.

trimLeft() and trimRight() do the same on each side of the string.

let myBadStr = "    hey bro, be chill \n"
let better = myBadStr.trim()

charAt(x) returns the character at a given index in a similar (but not identical) way to string[x].

charCodeAt(x) returns the character code at a given index of a string. This is a number representation of that character.

String.fromCharCode(x, ...) returns the string represented by a given character code or set of codes.

let num = "hello".charCodeAt(0)
console.log(num) // 97

let str = String.fromCharCode(55357,56393,55357)
console.log(str)

A Note on Regexps

One of the most powerful ways to work with strings is to use regular expression (regexp) syntax. This is a special language to work with strings, especially for search, replace, and validation operations. JS supports regexps by default.

Unfortunately regexps are quite complex and in fact comprise their own type of language (the regular languages). They are also notorious for being difficult to understand and debug. For these reasons we're not going to cover them in this part of the course, but will instead cover them as part of form validation in frontend development.

Exercise 2

  1. Using Math.random(), write a Spongebob meme generator. This should take an input string from the user. For each character, if the random number is above some threshold, the character should be uppercase in the output. If it's below that threshold, the character should by lowercase in the output.
  2. Starting from the following example code:
let triangle = [
  "    x",
  "   xx",
  "  xxx",
  " xxxx",
  "xxxxx",
]

for (row of triangle) {
  console.log(row)
}

Figure out a way to make the triangle lean the other way without ruining the shape.

Assignment

The Vigenere cipher takes some message (the plain text) and encodes it to make it harder to read. It does this by shifting characters according to some key phrase. For each character in the key phrase, shift the corresponding character in the plain text by a number corresponding to its position in the alphabet, starting from 0. If this is higher than 26, return to a.

For example:

Key: apple
Plain text: the bird is singing

Key letter: a (0)
Plain text: t (19)
Output: t (19)

Key letter: p (15)
Plain text: h (7)
Output: w (22)

The whole ciphertext is: twt mmrs xd wicvtrg

To experiment more you can use this tool.

Your task is to write a version of the Vigenere cipher which takes a key phrase and a plain text and outputs a cipher text. You must also write a decoder, which takes the cipher text and outputs the cipher text.

For security reasons, you must treat all input as suspicious and regularise it by:

  1. Removing all whitespace
  2. Converting the entire text to either uppercase or lowercase, but not a mixture of the two.
  3. Removing any non-alphabetical character (i.e. one that's not between a and z).

You must also make sure that your code loops around at Z. For example, if we shift Z with the key character b, it must output a, not a non-alphabetical character.