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

iOS字符串上标问题:相同后缀的数字th无法正确应用上标

问题分析

你的代码失效的核心原因是range(of:)的默认行为——它只会查找字符串中第一个匹配的子串。当你调用applySuperscriptAttributes(substring: "8th")时,函数会优先匹配到"28th"里的"8th"片段,导致第二次调用其实还是在修改第一个"th",完全没触及后面独立的"8th"。

修复方案

推荐用正则表达式批量处理所有符合数字+th格式的内容,既高效又不会漏处理:

let exampletString = "28th and 8th. I will be working on this task"
let convertedAttrString = NSMutableAttributedString(string: exampletString)

// 正则匹配:一个或多个数字后跟th的模式
let regex = try! NSRegularExpression(pattern: "(\\d+)th")
let matches = regex.matches(in: exampletString, range: NSRange(exampletString.startIndex..., in: exampletString))

for match in matches {
    // 定位到每个匹配项的"th"部分
    let thRange = NSRange(location: match.range.location + match.range.length - 2, length: 2)
    convertedAttrString.setAttributes([
        .font: UIFont.systemFont(ofSize: 10, weight: .regular),
        .baselineOffset: 5 // 必须加这个属性才能让文字上移成上标,数值可按需调整
    ], range: thRange)
}

补充说明

你原来的代码只修改了字体大小,但没有调整基线偏移,这样"th"只是变小,不会真正成为上标。添加.baselineOffset属性后,文字会向上偏移,达到标准的上标视觉效果。

如果你坚持要保留原函数的逐个调用方式,可以修改函数支持从指定位置开始查找,避免重复匹配:

var exampletString = "28th and 8th. I will be working on this task"
var convertedAttrString = NSMutableAttributedString(string: exampletString)

func applySuperscriptAttributes(substring: String, originalString: String, convertedString: NSMutableAttributedString, startAt: Int = 0){
    let searchRange = NSRange(location: startAt, length: originalString.count - startAt)
    guard let subRange = originalString.range(of: substring, options: [], range: searchRange),
          let convertedRange = Range(subRange, in: originalString)?.nsRange else {
        return
    }
    let thRange = NSRange(location: convertedRange.location + convertedRange.length - 2, length: 2)
    convertedString.setAttributes([
        .font: UIFont.systemFont(ofSize: 10, weight: .regular),
        .baselineOffset: 5
    ], range: thRange)
}

// 先处理"28th",再从它的结束位置开始查找"8th"
applySuperscriptAttributes(substring: "28th", originalString: exampletString, convertedString: convertedAttrString)
if let firstMatchRange = exampletString.range(of: "28th") {
    let startIndex = exampletString.distance(from: exampletString.startIndex, to: firstMatchRange.upperBound)
    applySuperscriptAttributes(substring: "8th", originalString: exampletString, convertedString: convertedAttrString, startAt: startIndex)
}

不过这种方式灵活性差,不如正则批量处理实用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 21:15:48