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

Swift中如何为NSAttributedString实现replacingOccurrences并保留原有属性?

哈哈,这个需求我刚处理过!确实直接转成String用replacingOccurrences会丢光原有属性,得换个思路——直接在NSMutableAttributedString上操作,遍历匹配到的目标词汇范围,叠加新属性即可。

核心思路

  1. 将原NSAttributedString转为可变的NSMutableAttributedString(方便修改属性)
  2. 用正则表达式全局匹配所有目标词汇的位置
  3. 遍历每个匹配范围,给这些范围叠加新属性(保留原有属性,冲突时新属性覆盖旧属性)

完整Swift代码示例

func addAttributeToTargetWords(of target: String, in originalAttrStr: NSAttributedString, newAttributes: [NSAttributedString.Key: Any]) -> NSAttributedString {
    let mutableAttrStr = NSMutableAttributedString(attributedString: originalAttrStr)
    
    do {
        // 自动转义目标字符串中的正则特殊字符(比如.、*这类)
        let escapedTarget = NSRegularExpression.escapedPattern(for: target)
        // 可根据需求添加匹配选项,比如.caseInsensitive实现不区分大小写匹配
        let regex = try NSRegularExpression(pattern: escapedTarget, options: [.caseInsensitive])
        let fullRange = NSRange(location: 0, length: mutableAttrStr.length)
        
        // 反向遍历匹配结果(虽然这里只是修改属性不改变文本长度,正向也可以,但反向是处理文本修改的通用好习惯)
        let matches = regex.matches(in: mutableAttrStr.string, options: [], range: fullRange).reversed()
        
        for match in matches {
            let targetRange = match.range
            // 叠加新属性,原有属性会被保留,冲突属性会被新值覆盖
            mutableAttrStr.addAttributes(newAttributes, range: targetRange)
        }
    } catch {
        print("正则创建失败:\(error.localizedDescription)")
        return originalAttrStr
    }
    
    return mutableAttrStr
}

关键细节说明

  • 正则转义:用NSRegularExpression.escapedPattern(for:)处理目标字符串,避免目标里的特殊正则字符(比如"a.b")破坏匹配逻辑。
  • 匹配选项:如果需要不区分大小写匹配,给正则添加.caseInsensitive选项即可;其他需求比如多行匹配,也可以追加对应的选项。
  • 保留原有属性:addAttributes(_:range:)方法不会清空原有属性,只是把新属性叠加进去——如果原有范围有和新属性冲突的键(比如都设置了foregroundColor),新属性的值会覆盖旧的,这符合大部分场景的预期。
  • 反向遍历:如果是修改文本内容(比如替换成其他字符串),正向遍历会导致后续范围偏移,但这里只是修改属性,文本长度不变,其实正向也没问题,但反向遍历是通用的安全写法,养成习惯准没错。

实际使用例子

// 构造一个带原有属性的富文本
let originalAttrStr = NSMutableAttributedString(string: "Hi there! Hello world, hello Swift!")
// 给前5个字符设置蓝色+18号字体
originalAttrStr.addAttributes([
    .foregroundColor: UIColor.blue,
    .font: UIFont.systemFont(ofSize: 18)
], range: NSRange(location: 0, length: 5))
// 给后面的普通文本设置黑色+14号字体
originalAttrStr.addAttributes([
    .foregroundColor: UIColor.black,
    .font: UIFont.systemFont(ofSize: 14)
], range: NSRange(location: 5, length: originalAttrStr.length - 5))

// 给所有"hello"添加红色属性
let redAttributes: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor.red]
let resultAttrStr = addAttributeToTargetWords(of: "hello", in: originalAttrStr, newAttributes: redAttributes)

// 结果:"Hello"和"hello"都会变成红色,同时保留原来的字体大小属性

这样操作下来,完全不需要把富文本转成普通字符串,原有属性丝毫不丢,还能精准给指定词汇加上新属性~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:10:06