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
相关产品推荐
相关产品推荐

