如何在 Kotlin 中使用动态字符串替换?
How to use dynamic string substitution in Kotlin?
我正在寻找一种 Kotlin 方法来将动态值替换为字符串。
实现方法已经很清楚了,就是想看看标准库里有没有类似的东西。
你能帮我找到一个给定 template
和 data
映射 returns 结果字符串的函数吗?
fun format(template: String, data: Map<String, Any>): String { /* magic */ }
format("${a} ${b} ${a}", mapOf("a" to "Home", "b" to "Sweet)) // -> "Home Sweet Home"
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"))
不比lukas.j的答案短,只是不同(使用正则表达式):
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)
}
我没有找到任何解决问题的标准。
所以这是一个平衡的 (readability/performance/extensibility) 解决方案,它还可以处理 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
}
}
我正在寻找一种 Kotlin 方法来将动态值替换为字符串。 实现方法已经很清楚了,就是想看看标准库里有没有类似的东西。
你能帮我找到一个给定 template
和 data
映射 returns 结果字符串的函数吗?
fun format(template: String, data: Map<String, Any>): String { /* magic */ }
format("${a} ${b} ${a}", mapOf("a" to "Home", "b" to "Sweet)) // -> "Home Sweet Home"
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"))
不比lukas.j的答案短,只是不同(使用正则表达式):
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)
}
我没有找到任何解决问题的标准。
所以这是一个平衡的 (readability/performance/extensibility) 解决方案,它还可以处理 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
}
}