如何更改字符串中的不同子串?

How to change different substrings in a string?

我有一个包含一定行数的文件。 我需要找到所有双字母并将第二个字母更改为地图中对应的字母。
应保留替换字母的大小写。
示例:
"kotlIn is a functional programming Language"
应变为
"kotlYn is a functionol programmyng Longuage"

fun changeChar(inputFileName: String, outputFileName: String) {
    val outputStream = File(outputFileName).bufferedWriter()
    val charsRegex = "([klmn][aei])".toRegex(setOf(RegexOption.IGNORE_CASE))
    val validChars = mapOf('a' to 'o', 'e' to 'u', 'i' to 'y')
    File(inputFileName).forEachLine { line ->
        val sb = StringBuilder(line).replace(charsRegex, /*here is my difficulty*/)
        outputStream.write(sb)
        outputStream.newLine()
    }
    outputStream.close()
}

我花了很多时间,但在互联网和标准 Kotlin 库上找不到解决方案。

没有任何正则表达式:

val validChars = mapOf('a' to 'o', 'e' to 'u', 'i' to 'y')
val chars = validChars.plus(validChars.map { it.key.toUpperCase() to it.value.toUpperCase() }.toMap())

var pattern = "klmn"
pattern = pattern.plus(pattern.toUpperCase())

val str = "kotlIn is a functional programming Language"
val result = str.mapIndexed { i, c ->
    if (i > 0) { if (pattern.contains(str[i -1])) chars.getOrDefault(c, c) else c } else c
}.joinToString("")
println(result)

将打印:

kotlYn is a functionol programmyng Longuage

试试这个。

fun main(args: Array<String>) {
    val str = "kotlIn is a functional programming Language"
    val validChars = mapOf("a" to "o", "e" to "u", "i" to "y" )
    val charsRegex = "(?=(.))([klmn][aei])(?<=(.))".toRegex(setOf(RegexOption.IGNORE_CASE))
    val found = charsRegex.findAll(str)
    var newStr= str
    found.forEach { f ->
        val m = f.value.toLowerCase()
        val idx = f.range
        val k = m.substring(1)
        val repStr = m.substring(0,1) + validChars.get(k)?.toUpperCase()
        newStr= newStr.replaceRange(idx,repStr)
       // println("$m found at indexes: $idx  ${validChars.get(k)} ${newStr}" )
     }
    println( "NewStr = ${newStr}")
}

版画

NewStr = kotlYn is a functionOl programmYng lOnguage

PS:我不太擅长 Kotlin,但我认为您可以稍微调整一下以获得准确的结果。

另一个惯用的解决方案是使用 replace(...) { ... } overload that accepts a lambda to handle each MatchResult:

转换匹配的字符串
val charsRegex = "[klmn][aei]".toRegex(RegexOption.IGNORE_CASE)
val validChars = mapOf('a' to 'o', 'e' to 'u', 'i' to 'y')

val result = line.replace(charsRegex) {
    val vowel = it.value[1]
    val validLetter = validChars.getValue(vowel.toLowerCase())
    val validCaseLetter = if (vowel.isLowerCase()) validLetter else validLetter.toUpperCase()
    it.value.take(1) + validCaseLetter
}

(runnable sample)

我会使用 replace,它也采用转换 lambda 作为热键。但我会将正则表达式更改为有两组。

  • 第一组是正后向,这意味着它会被匹配但不会被捕获,因为不必替换第一个字母
  • 第二组将被捕获,因为第二个字母必须由另一个字符替换

代码:

fun replaceInvalidPairs(line: String): String {
    val charsRegex = "(?<=[klmn])([aei])".toRegex(setOf(RegexOption.IGNORE_CASE))
    val validChars = mapOf('a' to 'o', 'e' to 'u', 'i' to 'y')

    return charsRegex.replace(line) {
        val secondLetter = it.groupValues.first().first()
        val replacement = validChars[secondLetter.toLowerCase()]!!
        (if (secondLetter.isUpperCase()) replacement.toUpperCase() else replacement).toString()
    }
}

结果:

kotlYn is a functionol programmyng Longuage