How to use dynamic string substitution in Kotlin?
I'm looking for a Kotlin way to do a dynamic values substitution into a string. It is clear how to implement it, just want to check if there is something similar in standard library.
Could you help me to find a function which given template
and data
map returns a resulting string with all template keys replaced with their values?
fun format(template: String, data: Map<String, Any>): String { /* magic */ }
format("${a} ${b} ${a}", mapOf("a" to "Home", "b" to "Sweet)) // -> "Home Sweet Home"
3 answers
-
answered 2022-01-19 17:31
lukas.j
fun format(template: String, data: Map<String, String>): String { var retval = template data.forEach { dataEntry -> retval = retval.replace("\${" + dataEntry.key + "}", dataEntry.value) } return retval } // The $ signs in the template string need to be escaped to prevent // string interpolation format("\${a} \${b} \${a}", mapOf("a" to "Home", "b" to "Sweet"))
-
answered 2022-01-19 19:08
Emanuel Moecklin
Not shorter than lukas.j's answer, just different (using Regex):
val regex = "\\\$\\{([a-z])}".toRegex() fun format(template: String, data: Map<String, String>) = regex.findAll(template).fold(template) { result, matchResult -> val (match, key) = matchResult.groupValues result.replace(match, data[key] ?: match) }
-
answered 2022-01-22 14:43
diziaq
I did not find any thing standard to solve the problem.
So here is a balanced (readability/performance/extensibility) solution also handling cases when some substitutions are undefined in dataMap.
makeString("\${a} # \${b} @ \${c}", mapOf("a" to 123, "c" to "xyz")) // => "123 # ??? @ xyz"
--
object Substitutions { private val pattern = Pattern.compile("\\$\\{([^}]+)\\}") fun makeString( template: String, dataMap: Map<String, Any?>, undefinedStub: String = "???" ): String { val replacer = createReplacer(dataMap, undefinedStub) val messageParts = splitWithDelimiters(template, pattern, replacer) return messageParts.joinToString("") } private fun createReplacer(dataMap: Map<String, Any?>, stub: String): (Matcher) -> String { return { m -> val key = m.group(1) (dataMap[key] ?: stub).toString() } } private fun splitWithDelimiters( text: String, pattern: Pattern, matchTransform: (Matcher) -> String ): List<String> { var lastMatch = 0 val items = mutableListOf<String>() val m = pattern.matcher(text) while (m.find()) { items.add(text.substring(lastMatch, m.start())) items.add(matchTransform(m)) lastMatch = m.end() } items.add(text.substring(lastMatch)) return items } }
How many English words
do you know?
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
how many words do you know
Powered by Examplum