Intermediate Exercism • kotlin

Strings

Lesson Overview

# Introduction

About Strings

A string in Kotlin is an immutable sequence of Unicode characters.

Immutable means that any operation on a string must return a new string: the original string can never change.

Unicode means that most of the world’s writing systems can be represented, but (in contrast to older languages such as C) there is no 1:1 mapping between characters and bytes. This will be discussed further in the Chars Concept.

A string is surrounded by double-quotes " ".

Some characters need escaping: \\, plus the usual non-printing characters such as \t (tab) and \n (newline).

val s = "Escape backslash \\."
// Escape backslash \.

Multi-line strings are surrounded by 3 double-quotes, and can contain arbitrary text (no need for escaping).

val multi = """I'm a
    multi-line
    string with special characters \ \t """
//I'm a
//    multi-line
//    string with special characters  \ \t 

Use trimIndent to remove the common indenting from the lines. This is useful for formatting the string:

val multi = """
    I'm a
      multi-line
    string""".trimIndent()

//I'm a
//  multi-line
//string

Alternatively, trimMargin lets you specify a delimiter. Each line in the String then begins after the delimiter. The delimiter defaults to |, but you can specify a different delimiter as a parameter. For example:

val multi = """
    |I'm a
    |  multi-line
    |string""".trimMargin()

//I'm a
//  multi-line
//string

val multi2 = """
    start>I'm a
    start>  multi-line
    start>string""".trimMargin("start>")

//I'm a
//  multi-line
//string

Strings can be concatenated with +, but this is best limited to short and simple cases. There are other and often better options.

String templates

Templates refers to what some other languages call “interpolation”.

If a string contains a dollar sign $, followed by an identifier, or contains braces ({expression}) surrounding an expression, those are substituted by respectively the value or the result of the expression.

val x = 42
val st = "x is $x, x squared is {x * x}"
// x is 42, x squared is 1764

String formatting

On the JVM platform (only), String.format() allows more precise formatting than string templates, with syntax similar to the (very old!) printf functions.

String.format("%s %.3f", "π ≈", 3.14159)
//π ≈ 3.142
Kotlin can be compiled to several different targets: the Java Virtual Machine, JavaScript, native binaries for Linux, Windows, Android and Apple, plus two variants of WebAssembly.

Essentially the same code can be used for each, but different capabilities in the target platforms mean some differences in which standard library functions are supported.

Exercism currently uses the JVM for testing.

String functions

Kotlin provides many functions to manipulate strings.

Mostly, these are extensions functions rather than members of the String class, though this has little effect on how we use them.

Kotlin's rather complex [documentation][ref-string-functions] pages hide extension functions in the default view.
At moment of writing this, the most valuable content is hidden in a tab named `Members & Extensions`.
Click it to expand this section and see all the members and extensions available on the `String` class.

[ref-string-functions]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/

The following example shows just a small selection of what is available:

val str = "Hello World!"

str.length              // => 12 (a property, not a function)
str.elementAt(6)        // => W
str.elementAtOrNull(20) // => null (index out of range)
str.substring(6, 11)    // => "World"
str.substringAfter(" ") // => "World!"

str.lowercase()         // => "hello world!"
str.uppercase()         // => "HELLO WORLD!"

str.startsWith("Hel")   // => true
str.endsWith("xyz")     // => false
str.indexOf("0")        // => 4

str.toCharArray()       // => [H, e, l, l, o,  , W, o, r, l, d, !]
"42".toInt() + 1        // => 43  (parsing; see also toFloat)

"Howdy!  ".trim()       // => "Howdy"

Building a string

Sometimes a long string needs to be built up in stages, for example within a loop.

Concatenating strings with + soon becomes neither elegant nor performant: immutability means that there is a lot of copying required.

Kotlin has various more efficient ways to combine multiple string:

  • String templates, described above.
  • `joinToString(), which will be covered in the Lists Concept.
  • Java’s StringBuilder, which is not regarded as particularly idiomatic Kotlin.
  • Kotlin’s buildString(), which wraps StringBuilder in a more concise and idiomatic syntax. This takes string-building logic as a lambda argument, which will be discussed in a later Concept.

In essence, a StringBuilder is a list-like structure, with many convenient methods. This is a small selection:

  • append() to add to the end.
  • insert() to add at a specified position.
  • deleteAt() and deleteRange() to remove from specified position(s).
  • toString() to convert to a normal string at the end: concatenating everything in a single, performant operation.
// Available, not recommended
val sb = StringBuilder()
sb.append("Hello ")
sb.append("World!")
sb.toString()
//Hello World!

A buildString() example, using syntax from later Concepts:

val countDown = buildString {
    for (i in 5 downTo 1) {
        append(i)
        append("_")
    }
}
// countDown is "5_4_3_2_1_"

Originally from Exercism kotlin concepts