Use regex for case-insensitive String.replace

KT-41799
This commit is contained in:
Ilya Gorbunov
2020-09-29 20:04:56 +03:00
parent 4a0109cf44
commit fafb4a7914
2 changed files with 29 additions and 19 deletions
@@ -77,27 +77,36 @@ public actual fun String.replace(oldChar: Char, newChar: Char, ignoreCase: Boole
*/
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun String.replace(oldValue: String, newValue: String, ignoreCase: Boolean = false): String {
// prefer case-insensitive platform implementation
if (!ignoreCase) return (this as java.lang.String).replace(oldValue, newValue)
if (ignoreCase) {
val matcher = Pattern.compile(oldValue, Pattern.LITERAL or Pattern.CASE_INSENSITIVE).matcher(this)
if (!matcher.find()) return this
val stringBuilder = StringBuilder()
var i = 0
do {
stringBuilder.append(this, i, matcher.start()).append(newValue)
i = matcher.end()
} while (matcher.find())
return stringBuilder.append(this, i, length).toString()
} else {
var occurrenceIndex: Int = indexOf(oldValue, 0, ignoreCase)
// FAST PATH: no match
if (occurrenceIndex < 0) return this
var occurrenceIndex: Int = indexOf(oldValue, 0, ignoreCase)
// FAST PATH: no match
if (occurrenceIndex < 0) return this
val oldValueLength = oldValue.length
val searchStep = oldValueLength.coerceAtLeast(1)
val newLengthHint = length - oldValueLength + newValue.length
if (newLengthHint < 0) throw OutOfMemoryError()
val stringBuilder = StringBuilder(newLengthHint)
val oldValueLength = oldValue.length
val searchStep = oldValueLength.coerceAtLeast(1)
val newLengthHint = length - oldValueLength + newValue.length
if (newLengthHint < 0) throw OutOfMemoryError()
val stringBuilder = StringBuilder(newLengthHint)
var i = 0
do {
stringBuilder.append(this, i, occurrenceIndex).append(newValue)
i = occurrenceIndex + oldValueLength
if (occurrenceIndex >= length) break
occurrenceIndex = indexOf(oldValue, occurrenceIndex + searchStep, ignoreCase)
} while (occurrenceIndex > 0)
return stringBuilder.append(this, i, length).toString()
var i = 0
do {
stringBuilder.append(this, i, occurrenceIndex).append(newValue)
i = occurrenceIndex + oldValueLength
if (occurrenceIndex >= length) break
occurrenceIndex = indexOf(oldValue, occurrenceIndex + searchStep, ignoreCase)
} while (occurrenceIndex > 0)
return stringBuilder.append(this, i, length).toString()
}
}
/**
+1
View File
@@ -895,6 +895,7 @@ class StringTest {
assertEquals("/b/", input.replace("ab", "/", ignoreCase = true))
assertEquals("-a-b-b-A-b-", input.replace("", "-"))
assertEquals("-a-b-b-A-b-", input.replace("", "-", ignoreCase = true))
}
@Test fun replaceFirst() {