You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中能否用NSRegularExpression实现JS式函数替换字符串?

当然可以实现!虽然Swift标准库的String没有像JavaScript那样直接支持带回调函数的replace方法,但借助NSRegularExpression,我们完全能复刻你想要的功能——甚至可以封装得更顺手。

核心思路

JavaScript里的replace回调,本质是遍历每一个正则匹配结果,用自定义逻辑处理捕获组后生成替换内容。在Swift中,我们可以用NSRegularExpression的enumerateMatches(in:options:range:)方法遍历所有匹配,然后手动处理替换逻辑,同时注意维护字符串长度变化带来的位置偏移。

针对你的需求的具体实现

先看直接实现的代码,我修正了正则让它正确捕获中间的文本内容,确保替换结果符合预期:

let originalText = "*Hello there*"
// 正则捕获:第一个*、中间的文本、第二个*
let regexPattern = "(\\*)(.*?)(\\*)"

do {
    let regex = try NSRegularExpression(pattern: regexPattern, options: .dotMatchesLineSeparators)
    let fullTextRange = NSRange(originalText.startIndex..., in: originalText)
    var modifiedText = originalText
    var offset = 0 // 记录替换导致的字符串长度偏移,避免后续匹配位置错误
    
    regex.enumerateMatches(in: originalText, options: [], range: fullTextRange) { match, _, _ in
        guard let match = match else { return }
        
        // 提取各个捕获组的内容
        guard let contentRange = Range(match.range(at: 2), in: originalText) else { return }
        let highlightedContent = String(originalText[contentRange])
        
        // 生成替换后的内容(对应你JS里的回调返回值)
        let replacement = "<i>" + highlightedContent + "</i>"
        
        // 计算当前在修改后字符串中的匹配范围(因为之前的替换会改变长度)
        let currentMatchRange = NSRange(location: match.range.location + offset, length: match.range.length)
        // 执行替换
        modifiedText = (modifiedText as NSString).replacingCharacters(in: currentMatchRange, with: replacement)
        
        // 更新偏移量:替换后的长度 - 原匹配片段的长度
        offset += replacement.count - match.range.length
    }
    
    print(modifiedText) // 输出: <i>Hello there</i>
} catch {
    print("正则表达式初始化失败: \(error.localizedDescription)")
}

封装成可复用的扩展

如果你的Markdown解析器需要多次用到这类替换逻辑,可以把它封装成String的扩展,用法会更接近JavaScript的replace:

extension String {
    /// 类似JS的replace方法,支持正则匹配+自定义回调生成替换内容
    func regexReplace(pattern: String, options: NSRegularExpression.Options = [], using callback: (NSTextCheckingResult, String) -> String) throws -> String {
        let regex = try NSRegularExpression(pattern: pattern, options: options)
        let fullRange = NSRange(startIndex..., in: self)
        var result = self
        var offset = 0
        
        regex.enumerateMatches(in: self, options: [], range: fullRange) { match, _, _ in
            guard let match = match else { return }
            // 调用回调生成替换内容
            let replacement = callback(match, self)
            // 修正当前匹配的位置
            let currentRange = NSRange(location: match.range.location + offset, length: match.range.length)
            result = (result as NSString).replacingCharacters(in: currentRange, with: replacement)
            // 更新偏移量
            offset += replacement.count - match.range.length
        }
        
        return result
    }
}

使用这个扩展的示例:

do {
    let input = "*Hello there*"
    let output = try input.regexReplace(pattern: "(\\*)(.*?)(\\*)") { match, original in
        guard let contentRange = Range(match.range(at: 2), in: original) else {
            return (original as NSString).substring(with: match.range) // 匹配失败则返回原内容
        }
        let content = String(original[contentRange])
        return "<i>" + content + "</i>"
    }
    print(output) // <i>Hello there</i>
} catch {
    print(error.localizedDescription)
}

注意事项

  1. NSRange与Swift Range的转换:NSRegularExpression基于NSRange工作,而Swift的String用的是Range<String.Index>,所以需要用Range(_:in:)方法来转换,避免索引错误。
  2. 偏移量维护:每次替换都会改变字符串的长度,如果不更新offset,后续的匹配位置会因为字符串长度变化而错位,这是实现中最容易踩坑的点。
  3. 正则匹配选项:如果你的Markdown文本包含换行,可以加上.dotMatchesLineSeparators选项,让正则的.匹配换行符。

内容的提问来源于stack exchange,提问作者linguine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:40:18