Skip to Content
Course content

89: String Extension Functions: trim, padStart, chunked

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen this a lot when developers are building internal tools or data importers: you're trying to format a raw string into a specific pattern—like a serial number or a product SKU—and you end up writing a mess of while loops and substring calls that eventually crash with a StringIndexOutOfBoundsException.

Take a look at this snippet. This is a classic "over-engineered" approach to formatting a user-provided ID to be exactly 10 digits, padded with zeros, and then split into groups of three for readability.

fun formatId(rawId: String): String {
    // Manually removing whitespace
    var cleaned = ""
    for (char in rawId) {
        if (char != ' ') cleaned += char
    }

    // Manually padding with zeros to reach 10 characters
    while (cleaned.length < 10) {
        cleaned = "0" + cleaned
    }

    // Manually chunking into groups of 3
    val result = cleaned.substring(0, 3) + "-" + 
                 cleaned.substring(3, 6) + "-" + 
                 cleaned.substring(6, 9) + "-" + 
                 cleaned.substring(9, 10)
    return result
}

// This works... until it doesn't.
println(formatId("  12345  ")) // 0000012345 -> 000-001-234-5

The IndexOutOfBounds Trap

The code above looks fine until you realize how fragile it is. If the input rawId happens to be longer than 10 characters after cleaning, the padding loop is skipped, but the substring calls are hardcoded. If you change the required length to 11, you have to rewrite every single index in that final string concatenation. It's a maintenance nightmare and a bug waiting to happen.

Cleaning and Padding the Right Way

Kotlin gives us extension functions that handle these common tasks in a single line. First, instead of looping through the string to remove spaces, use trim(). It handles leading and trailing whitespace instantly. Then, instead of a while loop, use padStart().

padStart(length, char) says: "If this string is shorter than length, add char to the beginning until it reaches that length. If it's already longer, just leave it alone."

val rawId = "  12345  "
val cleaned = rawId.trim().padStart(10, '0') 
// Result: "0000012345"

Breaking Strings Apart with chunked

Now, for the part where we split the string. Instead of calculating indices for substring, we use chunked(). This function splits a string into a list of strings, each with the maximum length you specify.

Here is how I would rewrite that entire formatId function using these extensions. It's cleaner, safer, and much easier to read.

fun formatId(rawId: String): String {
    return rawId.trim()
        .padStart(10, '0')
        .chunked(3) 
        .joinToString("-")
}

println(formatId("  12345  ")) // 000-001-234-5

I love chunked because it doesn't care if the total length is perfectly divisible by the chunk size. In the example above, the last chunk is just "5", and Kotlin handles that automatically without throwing an exception. By chaining trim(), padStart(), and chunked(), we've turned a fragile 15-line function into a robust 4-line pipeline.




📋 Practical Task

Build a Credit Card Masking Formatter

You are building a payment processing UI. You receive a raw string of numbers from a user that may contain accidental leading or trailing spaces. You need to process this string to meet the following requirements:

  • Remove any leading or trailing whitespace.
  • Ensure the string is exactly 16 characters long by padding the start with '0' if the user entered too few digits.
  • Split the 16-digit string into chunks of 4.
  • Join those chunks together with a space in between.

Write a function formatCardNumber(input: String): String that implements this logic and test it with the input " 54321 ". The expected output should be "0000 0000 0005 4321".

Rating
0 0

There are no comments for now.

to be the first to leave a comment.