String formatting is a critical concept in Kotlin that enables constructing dynamic string outputs in a readable and reusable way. This guide will dive into the various methods for formatting strings through code examples.
We will specifically explore:
- Foundational formatting syntax
- Number and date formatting
- Performance optimization
- Advanced templating
- Custom extensions
- Regex-powered manipulation
- JSON and HTML integration
- Building template engines
Let‘s get started!
Introduction to Kotlin String Formatting
First, let‘s quickly understand the need for formatting strings programmatically.
Hardcoding text strings directly into applications leads to tight coupling and maintainability issues. What if you need to support multiple languages or build a dynamic user interface?
This is where string formatting helps. It allows injecting values into predefined string templates dynamically.
For instance, instead of:
"Welcome back John!"
You can write:
"Welcome back ${user}!"
Here ${user} gets replaced with a name dynamically.
Common use cases include:
- Constructing log messages
- Building reusable UI text
- Displaying numbers and dates
- Generating files from templates
- Producing JSON/HTML strings
- Safe text interpolation
Kotlin provides several approaches to format strings flexibly which we will now explore.
Foundational String Interpolation
The simplest way is using string interpolation with ${} placeholders:
val user = "John"
println("Hello $user!") // Hello John!
Any valid expression can be embedded inside ${}:
println("Current year is ${Calendar.getInstance().get(Calendar.YEAR)}") // 2023
You can even insert function calls and logic flows:
if (user.isEmpty()) {
println("Welcome guest!")
} else {
println("Welcome back ${formatName(user)}!")
}
This keeps text separate from logic. But the syntax lacks fine-grained control.
Precision Formatting Specifiers
For numbers, dates etc. format specifiers like %d and %f help:
val price = 29.95
println("Price: %.2f" format(price)) // Price: 29.95
println("ID: %05d".format(25)) // ID: 00025
Some common specifiers are:
%s– String%d– Integer%f– Floating point number%e– Exponential float%x– Hexadecimal%c– Character
You can also left/right align, truncate and pad strings:
println("| %-15s |".format("Name")) // | Name |
Overall, basic interpolation and % specifiers cover many simple to moderate string building needs.
But there are more advanced approaches available…
Building Strings Lazily Using Templates
String templates provide a productive way to construct strings with dynamic data.
Unlike substitution, templates allow you to execute logic while appending text through a StringBuilder:
val result = buildString {
append("Start of text\n")
for (i in 1..5) {
append(randomParagraph())
append("\n")
}
append("End of text")
}
println(result)
Here buildString {} allows appending text within a block. The string gets rendered lazily only when result is used.
Benefits include:
- No need to declare temporary strings
- Efficient buffer allocation
- Cleaner logic flow
- Lazily computed
- Can add newlines easily
This approach shines for building JSON, XML, log files and other structured text outputs.
Optimizing String Performance
Let‘s now see some best practices around performance optimization with strings:
Use StringBuilder for heavy concatenations
// BAD
var sql = "SELECT * FROM "
sql += "users WHERE "
sql += "age > 20"
// GOOD
val sql = StringBuilder().append("SELECT * FROM ")
.append("users WHERE ")
.append("age > 20")
Overusing += causes repeated string allocations under the hood. StringBuilder helps reuse buffer space efficiently.
Extract constants as resources
Hardcoded strings bloat app size. Store them as constants:
const val USER_TEXT = "Welcome back {0}!"
println(USER_TEXT format user)
This allows easy reusability, localization and size optimization.
Enable optimizer flags
Use compiler flags like -opt-in=kotlin.RequiresOptIn to activate advanced optimizations and inline string operations.
Adopting these best practices ensures your formatter logic remains fast and lean.
Now let‘s tackle some real-world formatting challenges…
Formatting Numbers, Percentages, Times, Dates etc.
The kotlinx.datetime library contains handy extensions for formattingtemporal data types like dates, intervals, datetimes etc.
For instance, dates can be formatted in ISO8601, RFC3339, UI friendly strings and more:
import kotlinx.datetime.*
val now = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())
println(now.toIsoString())
// 2023-02-11T14:23:41.345+05:30
println(now.format(DateTimeFormatter.ofPattern("MMM dd, yyyy")))
// Feb 11, 2023
Similarly, times and intervals can be formatted as required:
val duration = 2.hours + 35.minutes
println(duration.formatIsoHours()) // PT2H35M
For number formatting, the kotlin.text library helps:
import kotlin.text.*
val pi = PI // 3.1415926535
println(pi.format(5)) // 3.14159
val miles = 1.25
println(miles.format("%.2f mi")) // 1.25 mi
You can format percentages, currency etc. in locales like French, Japanese easily:
val sales = 2342
val goal = 3000
print(getPercent(sales, goal)) // 78.1%
fun getPercent(num: Int, outOf: Int) =
((num.toDouble() / outOf.toDouble()) * 100.0)
.format("%.1f", Locale.FRENCH) + "%"
So you can use domain libraries like kotlinx.datetime and kotlin.text for handling common data type formats effectively.
Going Further with Advanced Templating
Now let‘s push Kotlin templating to the next level using some custom extensions…
Safely inject values
Injecting raw user input into strings risks XSS vulnerabilities:
println("Welcome ${params.name}!") // Unsafe!!
Implement a safe interpolator instead:
suspend fun TemplateContext.safeInject(value: String) {
append(encodeHtml(value))
}
// Usage:
buildString {
append("Welcome ")
safeInject(input) // no vulnerabilities!
}
Reuse boilerplate markup
Repeatedly appending the same HTML/XML tags gets verbose:
buildString {
append("<ul>\n")
for(item in items) {
append(" <li>$item</li>\n")
}
append("</ul>")
}
Extract a render function instead:
fun TemplateBuilder.renderList(
items: List<String>,
itemTag: String = "li"
) {
append("<ul>\n")
for(item in items) {
append(" <$itemTag>$item</$itemTag>\n")
}
append("</ul>\n")
}
// Usage:
buildString {
//...
renderList(items, "item")
}
This keeps templates DRY. You can build your own tag library on top of the formatter.
Manipulating Strings using Regex
The Regex class contains advanced helpers for text manipulation:
val regex = "\\{(.*?)\\}".toRegex()
val str = "{first_name} {last_name} joined {company}"
println( regex.replace(str) {
when (it.groups[1]!!.value) {
"first_name" -> "John"
"last_name" -> "Smith"
else -> "Acme"
}
})
// John Smith joined Acme
Here capture groups extract matched text, allowing programmatic replacement with values.
Other useful methods are:
split()– Split on patternmatches()– Check full string matchfind()– Search for matchupgroupBy()– Group all matches
Overall Regex enables search-replace operations on strings robustly.
Integrating Strings with JSON and HTML
String templating works nicely for producing JSON content:
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.*
data class User(val name: String, val age: Int)
fun main() {
val user = User("John", 32)
val json = buildString {
append(Json.encodeToString(user))
}
println(json)
// {"name":"John","age":32}
}
Here instead of parsing stringified JSON, you can encode objects directly into string outputs using kotlinx.serialization.
For HTML generation, Kotlinx HTML provides type-safe builders:
import kotlinx.html.*
fun main() {
val html = buildString {
appendHTML().html {
head {
title("My Page")
}
body {
h1 { +"Welcome!" }
p {
+"This bit of HTML was generated by Kotlin code!"
}
}
}
}
println(html)
}
The compiled HTML gets directly appended to the string output.
So templating integrates well with Kotlin‘s rich ecosystem libraries.
Building Your Own Template Engine
The string formatting APIs can form the foundation for building full-blown templating engines.
Let‘s design a simple example:
import kotlin.text.StringBuilder
class Templater {
fun buildString(builder: TemplateBuilder.() -> Unit): String {
val templateBuilder = TemplateBuilder()
builder(templateBuilder)
return templateBuilder.toString()
}
}
class TemplateBuilder : StringBuilder() {
fun inject(value: Any?) {
append(value)
}
fun title(str: String) {
append("")
}
// more tag functions...
}
fun main() {
val templater = Templater()
val template = templater.buildString {
title("Welcome!")
inject("Dear user,")
inject(getWelcomeText())
}
print(template)
}
Here templating logic gets extracted into a separate Templater class. It offers a clean DSL via the custom TemplateBuilder.
You can build rich text manipulation APIs on top of string formatting capabilities in this way.
Comparison with Other Languages
It helps to contextualize Kotlin‘s approach to string manipulation with some popular alternatives:
- Java: More verbose with
+concatenations. No multi-line support. Reliance onStringBuilder. Lacks good text templating option. - Python: Powerful
f-stringinterpolation including expressions. Formatting and padding also available. But building strings incrementally needs separateiobuffer. - JavaScript: Template literals provide simple substitution and multiline access like Kotlin raw strings. Plus tagged templates allow library integrations. But weak compared to Kotlin‘s strong typing, regex support and kotlinx libraries.
- C#: Rich substitution syntax covering inline expressions, formatted specifiers etc. Interpolation also usable with
System.Consolewrites.
Overall Kotlin provides a comprehensive toolkit combining substitution, templates and utilities like StringBuilder, Regex etc. This offers a flexible platform for varied text manipulation needs.
Key Takeaways
We covered a lot of ground around string formatting in Kotlin!
Here are the vital takeaways:
- Prefer string templates over interpolation for dynamic text generation
- Use format specifiers like
%dand%.2ffor fine-grained control - Extract constants and utilize
StringBuilderfor optimization - Build custom interpolators for safety and reusability
- Integrate formatting with JSON, HTML libraries
- Enable advanced regex search-replace operations
- Construct complete templating engines using formatter foundations
This demonstrates that string handling is a Kotlin strong suit thanks to the multi-paradigm facilities.
Adopting these best practices will undoubtedly take your skills to an expert level.
So leverage Kotlin‘s formatting powers to craft exceptional string manipulation solutions!


