Strings & Templates
Text is everywhere in programs: names, addresses, messages, receipts, search boxes. In Kotlin, text is stored in the String type. Kotlin makes strings pleasant to work with: you can drop values straight into text with templates, and the standard library has a function for almost every common job.
In this lesson you will build strings with templates, use the most important string functions, write multi-line text with raw strings, and learn the newer multi-dollar syntax for text that contains many $ signs.
String templates
A string template puts a value inside a string. Write $name for a simple variable, and ${...} for anything more: a calculation, a function call or a property.
fun main() {
val name = "Farhan"
val items = 3
val pricePerItem = 249
println("Hello, $name!")
println("$name bought $items items for Rs ${items * pricePerItem}.")
println("The name has ${name.length} letters")
println("First letter: ${name[0]}, last letter: ${name.last()}")
}Hello, Farhan! Farhan bought 3 items for Rs 747. The name has 6 letters First letter: F, last letter: n
A few things to notice:
name.lengthis the number of characters.name[0]gets a single character by its index (position). Indexes start at0, so the last index islength - 1.name.last()gets the last character without you working out the index.
You can also join strings with +, as in "Hello, " + name, but templates are easier to read, and Kotlin developers prefer them.
Common string functions
Strings in Kotlin are immutable: no function changes the original string. Each function returns a new string, so you store or print the result.
fun main() {
val raw = " Kabir Singh "
val name = raw.trim()
println("[$name]")
println(name.uppercase())
println(name.lowercase())
println(name.startsWith("Kab"))
println(name.contains("singh"))
println(name.contains("singh", ignoreCase = true))
println(name.indexOf("S"))
println(name.substring(0, 5))
println(name.replace("Singh", "Sharma"))
println(name.split(" "))
}[Kabir Singh] KABIR SINGH kabir singh true false true 6 Kabir Kabir Sharma [Kabir, Singh]
trim()removes spaces from both ends, very useful for user input.contains,startsWithandendsWithanswer yes or no questions. Many functions acceptignoreCase = true.indexOfreturns the position of the first match, or-1if there is none.substring(0, 5)takes characters from index 0 up to, but not including, index 5.split(" ")breaks the text into a list of pieces.
Other everyday functions include isEmpty(), isBlank() (empty or only spaces), take(3) (first three characters), drop(3) (all but the first three) and lines() (split into lines).
Padding, repeating and reversing
When you print tables or receipts in a console, you want columns to line up. padEnd adds spaces on the right until the string reaches a length, and padStart adds them on the left.
fun main() {
println("=".repeat(20))
println("Tea".padEnd(12) + "15".padStart(8))
println("Samosa".padEnd(12) + "20".padStart(8))
println("Jalebi".padEnd(12) + "60".padStart(8))
println("=".repeat(20))
println("7".padStart(3, '0'))
println("level".reversed())
}==================== Tea 15 Samosa 20 Jalebi 60 ==================== 007 level
padStart(3, '0') pads with zeros instead of spaces, which is handy for roll numbers and order IDs. "level".reversed() is still "level", because it is a palindrome.
Comparing strings and working with characters
Use == to compare the contents of two strings. For a case-insensitive check, use equals(other, ignoreCase = true). The < and > operators compare strings in dictionary order (by character codes, so all capital letters come before lowercase ones).
fun main() {
println("Pune".equals("PUNE", ignoreCase = true))
println("apple" < "banana")
val pin = "1100a1"
println(pin.length == 6 && pin.all { it.isDigit() })
println("rohtak".replaceFirstChar { it.uppercase() })
val code = buildString {
append("EC")
append('-')
append(2026)
}
println(code)
}true true false Rohtak EC-2026
pin.all { it.isDigit() } checks every character; the part in braces is a small function called a lambda, which you will study in Lambdas & Higher-Order Functions. buildString collects pieces efficiently, which is better than adding strings with + inside a long loop.
Raw strings and trimIndent
A raw string is written between triple quotes """. It can span many lines, and backslashes are not escape characters inside it, which makes Windows paths and regular expressions easier to write. Templates still work.
fun main() {
val name = "Meera"
val receipt = """
Receipt for $name
Item: Notebook x 4
Total: Rs ${4 * 45}
""".trimIndent()
println(receipt)
val path = """C:\Users\meera\notes.txt"""
println(path)
}Receipt for Meera Item: Notebook x 4 Total: Rs 180 C:\Users\meera\notes.txt
trimIndent() removes the shared indentation from every line and drops the blank first and last lines, so you can indent the text nicely inside your code.
Common mistakes
- Expecting a function to change the string.
name.uppercase()on its own line does nothing useful. Writeval upper = name.uppercase(). - Template stops too early.
"$user.name"insertsuserand then the text.name. Use"${user.name}"for properties. - Index out of range.
name[10]on a six-letter name crashes withStringIndexOutOfBoundsException. Checklengthfirst, or usegetOrNull(10), which returnsnullinstead. - Comparing with different case.
"Pune" == "pune"isfalse. Normalise withlowercase()or useignoreCase = true.
Key points
$nameand${expression}put values inside strings; prefer templates over+.- Strings are immutable; functions such as
trim(),uppercase()andreplace()return new strings. - Indexes start at
0;substring(a, b)excludes indexb. padStart,padEndandrepeathelp line up console output.- Raw strings use
"""and work well withtrimIndent(). - Kotlin 2.2 added
$$"..."strings, where a single$is plain text.
Exercise
Write a program that takes the messy input " priya SHARMA , jaipur " and prints a clean profile line: Name: Priya Sharma | City: Jaipur | Initials: PS. Use split(","), trim(), lowercase() and replaceFirstChar. (Hint: split the name into first and last name with split(" ").)
Show solution
fun main() {
val input = " priya SHARMA , jaipur "
val parts = input.split(",")
val names = parts[0].trim().split(" ")
val first = names[0].lowercase().replaceFirstChar { it.uppercase() }
val last = names[1].lowercase().replaceFirstChar { it.uppercase() }
val city = parts[1].trim().replaceFirstChar { it.uppercase() }
val initials = "${first[0]}${last[0]}"
println("Name: $first $last | City: $city | Initials: $initials")
}Name: Priya Sharma | City: Jaipur | Initials: PS
Lower-casing first and then capitalising the first letter fixes any mix of cases, such as SHARMA.
Quick Quiz
1. What does "Kotlin".substring(1, 4) return?
It starts at index 1 and stops before index 4, giving characters 1, 2 and 3.
2. How do you insert the length of name into a string?
Braces are needed for anything more than a simple variable name.
3. What does " hi ".trim() do to the original variable?
Strings are immutable, so trim() returns a new string.
4. In a $$"""...""" string, what is $id?
With two leading dollar signs, a template needs $$, so a single $ is literal text.
Learn Kotlin with a mentor
Free lessons get you started. Our Programming & Software Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
