Text and string interpolation
Text as a value you can ask questions of, the s before the quotes that puts a name inside a sentence, and the methods that measure, trim and split a line.
Text is a value like any other
A String is text between double quotes, and once it has a name it behaves like any other value: you can print it, keep it in a list, hand it to a function and join it to another piece with +. That plus sign has been doing the work since the first chapter, and it is still the plainest way to build a line.
Text also answers questions about itself. length counts the characters, trim removes the spaces at either end, toUpperCase hands back a shouting copy, and contains answers a Boolean about whether a piece of text appears. None of them change the original, because a String cannot be altered: every method returns a new one.
Interpolation, and the dollar sign
Writing "Hello, " + name works, but it gets noisy once a line has three or four pieces in it. Scala has a shorter form: put an s in front of the quotes and write the name inside with a $. s"Hello, $name" produces the same text, and the name can sit anywhere in the sentence.
Only a plain name goes straight after the $. For anything more involved — a method call, a field, arithmetic — you wrap it in braces, which is the form you will meet in other code. Here the examples keep to plain names and join the rest with +, which stays readable and works everywhere.
Measuring and splitting
split is how one line becomes several: give it the text to break on and it hands back an array of pieces, which you read with round brackets — parts(0) is the first and parts.length counts them. A comma, a space and a dash are the usual separators.
Case matters to every one of these methods. contains("two") and contains("Two") are different questions, and trim only takes off the spaces at the ends, never the ones between the words. That is usually what you want, and when it is not, calling toLowerCase first is the standard repair.
What split hands back
split does not return another String; it returns an Array[String], a fixed-size row of pieces. You read a piece with round brackets and a position, and positions start at zero: parts(0) is the first piece and parts.length counts them. Asking for parts(3) on a three-piece array throws, and the program stops on that line.
The separator is a regular expression, not a plain piece of text. A comma, a space and a dash mean themselves, but a dot matches any character, so "a.b".split(".") does not split on the dot at all. A separator that repeats produces empty pieces between the repeats, which is why trimming the line before splitting is usually the first step.
Printing the array directly shows its address rather than its contents. Print the pieces one at a time, or join them with mkString, and you see the values the array actually holds. The original text is never changed by any of this: split returns a new array and leaves the string exactly as it was.
Comparing text, and asking it questions
Text compares with ==: name == "Ada" asks whether the two strings hold the same characters. Scala has no separate text-comparison operator, because == on a String already compares the contents rather than the two objects.
A few more methods are worth knowing by name: startsWith, endsWith, indexOf and replace. Each returns a value and leaves the original alone, so name.replace("a", "o") gives a new string and name still holds the old one. isEmpty is the shortest way to ask whether there is any text at all.
Two mistakes are easy to make with text: split(".") treats the dot as "any character" and returns an empty array, and printing the result of split shows something like [Ljava.lang.String;@... rather than the words. Use split("\\.") for a literal dot, and print the pieces or call mkString.
Try these next
- Split
"red,green,blue"on the comma and print each piece with its position. - Trim
" Ada "and print the length before and after. - Join three words with
mkString(" / ")and count the characters in the result.
Building and taking apart a line
val name = "Ada"
val greeting = s"Hello, $name"
println(greeting) // Hello, Ada
println(greeting.length) // 10
println(greeting.toUpperCase) // HELLO, ADA
val padded = " roomy "
println(padded.length) // 9
println(padded.trim) // roomy
val parts = "one,two,three".split(",")
println(parts.length) // 3
println(parts(0)) // one
println("one,two".contains("two")) // trueA name tag
Run it and follow one line through its versions: interpolated, joined, counted and shouted. Then add a `s"..."` line of your own that uses both names, and print the length of the result.
Taking a record apart
Run it and follow the raw line as it becomes three clean fields. Then add a fourth field to the input, print it, and build a new line with `mkString(" | ")`.
length is written without brackets — name.length, not name.length(). The methods that take an argument use brackets, as in "one,two".split(",") and "abc".contains("b"), and the ones that take nothing do not.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
What does s"Hello, $name" produce when name holds Ada?
