Contrast replace (String vs Char vs regex overloads), removePrefix/removeSuffix, and String.format("%.2f"). What are the common mistakes?
answer
- replace(Char/String) = literal, replaces ALL; replace(Regex) = pattern + $1
- String overload does NOT interpret regex
- removePrefix/Suffix strip only if present, else unchanged
- format is LOCALE-sensitive — pin Locale.US/ROOT
- %.2f rounds, not truncates; mismatch throws
basics
~10 sreplace swaps text for other text. removePrefix/removeSuffix strip a known beginning or ending only if it's there. format builds a string from a pattern, like showing a number with two decimals using %.2f.
solid answer
~40 sreplace has several overloads: replace(old: Char, new: Char), replace(old: String, new: String) — both do literal, non-regex replacement of ALL occurrences (with an ignoreCase flag) — and replace(regex: Regex, replacement: String) for pattern-based replacement where the replacement supports $1 group refs. A frequent mistake is expecting the String overload to interpret regex (it does not) or vice versa. removePrefix/removeSuffix remove a literal prefix/suffix only if present, returning the original string unchanged otherwise (unlike substringAfter's whole-string default, these are about exact ends). String.format("%.2f", x) uses Java-style format specifiers and is LOCALE-sensitive — it may emit a comma decimal separator in some locales; use String.format(Locale.US, ...) or "%.2f".format(Locale.ROOT, x) for stable output. format throws on argument/specifier mismatch.
code
kotlin · 14 linesimport java.util.Locale
fun money(amount: Double): String =
"$" + String.format(Locale.US, "%.2f", amount) // stable decimal point
fun normalizePath(p: String): String =
p.removeSuffix("/").removePrefix("/")
fun maskDigits(s: String): String =
s.replace(Regex("\\d"), "*")
println(money(2.5)) // $2.50
println(normalizePath("/api/")) // api
println(maskDigits("id-42")) // id-**go deeper
Knows replace swaps text and %.2f shows two decimals; uses removePrefix to strip a known start.
Distinguishes literal vs regex replace overloads and that removePrefix is a no-op when absent.
Flags the locale trap in format, uses $1 group refs in regex replace, and knows replaceFirst and rounding semantics.
Mandates locale-pinned formatting and BigDecimal for money across services, preventing subtle i18n/precision defects.
## replace — three behaviors ```kotlin fun String.replace(oldChar: Char, newChar: Char, ignoreCase: Boolean = false): String fun String.replace(oldValue: String, newValue: String, ignoreCase: Boolean = false): String fun CharSequence.replace(regex: Regex, replacement: String): String ``` - The `Char` and `String` overloads are **literal** — they replace **every** occurrence and do **not** treat the pattern as a regex. `"a.b.c".replace(".", "-")` yields `"a-b-c"` (the dot is literal here). - The `Regex` overload matches a pattern; the replacement string may reference capture groups with `$1`, `${name}`, and escape a literal `$`/`\` with a backslash. ```kotlin "2026-06-21".replace(Regex("(\\d+)-(\\d+)-(\\d+)"), "$3/$2/$1") // "21/06/2026" ``` **Common mistake:** passing a regex-looking string to the `String` overload expecting metacharacters to work — they are treated literally. Conversely, building a `Regex` for a fixed substring is needless overhead. ## removePrefix / removeSuffix ```kotlin fun String.removePrefix(prefix: CharSequence): String fun String.removeSuffix(suffix: CharSequence): String fun String.removeSurrounding(delimiter: CharSequence): String ``` They strip the given literal prefix/suffix **only if it is actually present**; otherwise they return the original string unchanged. This makes them safe and idempotent for normalizing things like trailing slashes or known prefixes: ```kotlin "https://x".removePrefix("https://") // "x" "plain".removePrefix("https://") // "plain" (unchanged) "/api/".removeSuffix("/") // "/api" ``` They are **not** general replace — they only touch the very start/end. ## String.format and "%.2f" Kotlin exposes Java's `Formatter` via `String.format(format, vararg args)` and the extension `String.format(vararg args)` / `String.format(locale, vararg args)`. ```kotlin String.format("%.2f", 3.14159) // "3.14" (or "3,14" in some locales!) String.format(Locale.US, "%.2f", 3.14159) // "3.14" always "%05.2f".format(Locale.ROOT, 3.1) // "03.10" ``` **Key gotchas:** - **Locale sensitivity:** the default `String.format("%.2f", x)` uses the JVM default locale, which can produce a comma decimal separator (e.g., `"3,14"`) and break parsing or APIs. Always pass an explicit `Locale` (`Locale.US`/`Locale.ROOT`) for machine-facing output. - `%.2f` rounds (half-up via the formatter), it does not truncate. - A mismatch between specifiers and argument types/count throws an `IllegalFormatException`. - For currency/precise decimals prefer `BigDecimal` with explicit rounding rather than `%f`. ## Mental model Use `replace` for substitutions, `removePrefix/Suffix` for trimming known ends, and locale-pinned `format` for numeric/text layout.
- Why might "%.2f".format(price) print "19,99" on a colleague's machine but "19.99" on yours?format uses the JVM default locale; locales like German use a comma decimal separator. Pin Locale.US/ROOT for deterministic output.
- How do you replace only the FIRST occurrence?The literal overloads replace all. Use replaceFirst(old, new) or replaceFirst(regex, replacement) for a single replacement.
saying these in an interview costs you the question
- Expecting replace(".", "x") to behave like a regex
- Ignoring locale in String.format leading to comma separators
- Thinking removePrefix throws or returns empty when prefix absent
- Using %.2f / Double for monetary values needing exact rounding
- Assuming replace touches only the first match