如何在 Kotlin 正则表达式中使用反向引用?

5

我试图在Kotlin中使用带有反向引用的正则表达式,以以下方式替换String的占位符:

源: "This is a %s with %02d whatever"

目标: "This is a <s/> with <02d/> whatever"

所以我正在寻找类似于以下内容但具有适当语法的东西:

private fun escapePlaceHolders(text: String): String {
    return """%([^ ]+?)""".toRegex().replace(text, "<\1/>")
}

显然,这段代码甚至无法编译,更不用说工作了。问题在于我不知道如何在替换函数中使用后向引用,如果有可能的话。

2个回答

9
最简单的方法是按照Wiktor Stribiżew在被接受的答案中所述
如果您不仅需要引用而且需要任意转换匹配项以进行替换,则有一个强大的替代方案,即带有如下签名的replace重载fun CharSequence.replace(regex: Regex, transform: (MatchResult) -> CharSequence): String 可以按以下方式使用它:
"""%([^ ]+)""".toRegex().replace(text) { "<${it.groupValues[1]}/>" }

8

您可以使用

val text = "This is a %s with %02d whatever"
val rx = """%(\d*[a-z])""".toRegex()
println(text.replace(rx, "<$1/>")) // => This is a <s/> with <02d/> whatever

如果您需要在替换之前对组值执行额外操作,例如将值转换为大写或小写,请使用.replace方法的重载和transform参数:
// To get the same result as above, i.e. wrap Group 1 with < >:
println(rx.replace(text) { "<${it.groupValues[1].uppercase()}>" })
// =>  This is a <S> with <02D> whatever
// If you just want to turn Group 1 value to upper case:
println(rx.replace(text) { it.groupValues[1].uppercase() })
// => This is a S with 02D whatever

查看 Kotlin演示1Kotlin演示2

详情

  • % - 一个%字符
  • (\d*[a-z]) - 一组(稍后在替换模式中使用$1引用):
    • \d* - 0个或多个数字
    • [a-z] - 一个小写ASCII字母。

请随意调整模式以适应您的输入,其思路保持不变。


非常感谢。我的正则表达式也是错的。它适用于%s,但因某种原因在%02d上失败了。 - Fran Marzoa
1
@FranMarzoa,你的 ([^ ]+?) 只匹配了一个非空格字符。你可以尝试使用 ([^ ]+)。但我怀疑它会匹配太多。 - Wiktor Stribiżew
如果在它后面加一个空格,应该就不会出问题了。但无论如何,你的代码完美运行且非常简单,非常感谢你。 - Fran Marzoa
好吧,只是为了测试而已,它确实可以像你建议的那样不带问号就能工作。https://rextester.com/WHT29374 - Fran Marzoa
1
当然,正则表达式末尾的惰性量化模式始终匹配最少数量的字符: *? / ?? 不匹配任何字符,并且 +? 只匹配一个字符。 - Wiktor Stribiżew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接