代码之家  ›  专栏  ›  技术社区  ›  GhostCat

访问匹配结果的更好方法?

  •  2
  • GhostCat  · 技术社区  · 6 年前

    我的要求是转换一些文本消息id。输入是

    a.messageid=X0001E
    b.messageid=Y0001E
    

    任务是把它变成

    a.messageid=Z00001E
    b.messageid=Z00002E
    

    换句话说:每行取第一部分(比如: a. ),并附加一个稍有不同的id。

    我目前的解决方案:

    val matcherForIds = Regex("(.*)\\.messageid=(X|Y)\\d{4,6}E")  
    var idCounter = 5
    
    fun transformIds(line: String): String {
        val result = matcherForIds.matchEntire(line) ?: return line
        return "${result.groupValues.get(1)}.messageid=Z%05dE".format(messageCounter++)
    }
    

    这个 作品 ,但是找到我第一次比赛的方法 "${result.groupValues.get(1)} 不是很优雅。

    有没有更好的阅读/更简洁的方法来访问第一个匹配项?

    2 回复  |  直到 6 年前
        1
  •  1
  •   Wiktor Stribiżew    6 年前

    不需要单独的函数就可以得到结果:

    val line = s.replace("""^(.*\.messageid=)[XY]\d{4,6}E$""".toRegex()) { 
        "${it.groupValues[1]}Z%05dE".format(messageCounter++) 
    }
    

    但是,如果你需要 format 这个 messageCounter 在结果中,不能只使用字符串替换模式,也不能去掉 ${it.groupValues[1]} .

    另外,请注意:

    • 您可以通过三个带引号的字符串文字去掉双反斜杠
    • 不需要添加 .messageid= 如果将该部分捕获到组1中(请参见 (.*\.messageid=) )
    • 不需要捕捉 X Y 既然你以后不用了, (X|Y) 可以替换为更有效的字符类 [XY] .
    • 这个 ^ $ 确保模式与整个字符串匹配,否则将不匹配,字符串将按原样返回,无需任何修改。

    Kotlin demo online .

        2
  •  1
  •   Roland    6 年前

    也许不是你真正想要的,但也许是。如果您首先确保(过滤)感兴趣的行,然后只替换需要替换的行,例如使用以下转换函数:

    val matcherForIds = Regex("(.*)\\.messageid=(X|Y)\\d{4,6}E")
    val idRegex = Regex("[XY]\\d{4,6}E")
    var idCounter = 5
    
    fun transformIds(line: String) = idRegex.replace(line) {
      "Z%05dE".format(idCounter++)
    }
    

    使用以下过滤器:

    "a.messageid=X0001E\nb.messageid=Y0001E"
      .lineSequence()
      .filter(matcherForIds::matches)
      .map(::transformIds)
      .forEach(::println)
    

    如果还有其他相关的字符串需要保留,那么也可以使用下面的字符串,但不如最后的解决方案好:

    "a.messageid=X0001E\nnot interested line, but required in the output!\nb.messageid=Y0001E"
      .lineSequence()
      .map {
        when {
          matcherForIds.matches(it) -> transformIds(it)
          else -> it
        }
      }
      .forEach(::println)
    

    或者(现在只是复制Wiktors regex,因为它已经包含了我们需要的所有内容(从行首完全匹配 ^ 到线路末端 $ ,等等):

    val matcherForIds = Regex("""^(.*\.messageid=)[XY]\d{4,6}E$""")
    fun transformIds(line: String) = matcherForIds.replace(line) {
      "${it.groupValues[1]}Z%05dE".format(idCounter++)
    }
    

    这样可以确保完全匹配所需输入的行被替换,其他行被保留但不被替换。