diff --git a/Sources/SkipLib/Regex.swift b/Sources/SkipLib/Regex.swift index 7ec1bf9..58e7370 100644 --- a/Sources/SkipLib/Regex.swift +++ b/Sources/SkipLib/Regex.swift @@ -61,6 +61,24 @@ public struct Regex : RegexComponent { public func replace(_ string: String, with replacement: String) -> String { return _regex.replace(string, replacement) } + + public func replace(_ string: String, maxReplacements: Int = Int.max, with replacement: (Match) throws -> String) rethrows -> String { + if maxReplacements <= 0 { + return string + } + + var replacementCount = 0 + return _regex.replace(string) { match in + let replacementValue: String + if replacementCount < maxReplacements { + replacementCount += 1 + replacementValue = try replacement(Match(match: match)) + } else { + replacementValue = match.value + } + return java.util.regex.Matcher.quoteReplacement(replacementValue) + } + } } #endif diff --git a/Sources/SkipLib/Skip/String.kt b/Sources/SkipLib/Skip/String.kt index 0cffa95..bfa773f 100644 --- a/Sources/SkipLib/Skip/String.kt +++ b/Sources/SkipLib/Skip/String.kt @@ -437,6 +437,10 @@ fun String.replacing(regex: Regex, with: String): String { return regex.replace(this, with) } +fun String.replacing(regex: Regex, maxReplacements: Int = Int.max, with: (Regex.Match) -> String): String { + return regex.replace(this, maxReplacements = maxReplacements, with = with) +} + operator fun String.Companion.invoke(format: String, vararg args: Any): String { return format.kotlinFormatString.format(*args) } diff --git a/Sources/SkipLib/String.swift b/Sources/SkipLib/String.swift index a6489ce..5e093df 100644 --- a/Sources/SkipLib/String.swift +++ b/Sources/SkipLib/String.swift @@ -67,6 +67,10 @@ public struct String: RandomAccessCollection { public func replacing(_ regex: Regex, with: String) -> String { fatalError() } + + public func replacing(_ regex: Regex, maxReplacements: Int = Int.max, with replacement: (Regex.Match) throws -> String) rethrows -> String { + fatalError() + } } public struct Substring: RandomAccessCollection { diff --git a/Tests/SkipLibTests/RegexTests.swift b/Tests/SkipLibTests/RegexTests.swift index 587c28c..ad4b349 100644 --- a/Tests/SkipLibTests/RegexTests.swift +++ b/Tests/SkipLibTests/RegexTests.swift @@ -24,6 +24,10 @@ import Testing #expect("Hello, Alice!" == "Hello, Bob!".replacing(try Regex("Hello, (\\w+)!"), with: "Hello, Alice!")) + #expect("1zz1" == "1z1".replacing(try Regex("([a-z])"), with: { match in + return match[1].substring! + match[1].substring! + })) + #if SKIP // skip: regular expression support is incomplete return