Swift String 范围和 NSString 范围不“兼容”。
例如,像? 这样的表情符号算作一个 Swift 字符,但算作两个 NSString
字符(所谓的 UTF-16 代理对)。
因此,如果字符串
包含这样的字符。示例:
let text = "???Long paragraph saying!"
let textRange = text.startIndex..<text.endIndex
let attributedString = NSMutableAttributedString(string: text)
text.enumerateSubstringsInRange(textRange, options: NSStringEnumerationOptions.ByWords, { (substring, substringRange, enclosingRange, stop) -> () in
let start = distance(text.startIndex, substringRange.startIndex)
let length = distance(substringRange.startIndex, substringRange.endIndex)
let range = NSMakeRange(start, length)
if (substring == "saying") {
attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: range)
}
})
println(attributedString)
输出:
???长段落{
}ph 说{
NSColor = "NSCalibratedRGBColorSpace 1 0 0 1";
}ing!{
}
如您所见,“ph say”已被标记为属性,而不是“saying”。
由于NS(Mutable)AttributedString 最终需要一个NSString 和一个NSRange,它实际上是
最好先将给定的字符串转换为NSString。然后substringRange
是NSRange,您不必再转换范围:
let text = "???Long paragraph saying!"
let nsText = text as NSString
let textRange = NSMakeRange(0, nsText.length)
let attributedString = NSMutableAttributedString(string: nsText)
nsText.enumerateSubstringsInRange(textRange, options: NSStringEnumerationOptions.ByWords, { (substring, substringRange, enclosingRange, stop) -> () in
if (substring == "saying") {
attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: substringRange)
}
})
println(attributedString)
输出:
???长段{
}说{
NSColor = "NSCalibratedRGBColorSpace 1 0 0 1";
}!{
}
Swift 2 更新:
let text = "???Long paragraph saying!"
let nsText = text as NSString
let textRange = NSMakeRange(0, nsText.length)
let attributedString = NSMutableAttributedString(string: text)
nsText.enumerateSubstringsInRange(textRange, options: .ByWords, usingBlock: {
(substring, substringRange, _, _) in
if (substring == "saying") {
attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: substringRange)
}
})
print(attributedString)
Swift 3 更新:
let text = "???Long paragraph saying!"
let nsText = text as NSString
let textRange = NSMakeRange(0, nsText.length)
let attributedString = NSMutableAttributedString(string: text)
nsText.enumerateSubstrings(in: textRange, options: .byWords, using: {
(substring, substringRange, _, _) in
if (substring == "saying") {
attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.red, range: substringRange)
}
})
print(attributedString)
Swift 4 更新:
从 Swift 4 (Xcode 9) 开始,Swift 标准库
提供在Range<String.Index> 和NSRange 之间转换的方法。
不再需要转换为NSString:
let text = "???Long paragraph saying!"
let attributedString = NSMutableAttributedString(string: text)
text.enumerateSubstrings(in: text.startIndex..<text.endIndex, options: .byWords) {
(substring, substringRange, _, _) in
if substring == "saying" {
attributedString.addAttribute(.foregroundColor, value: NSColor.red,
range: NSRange(substringRange, in: text))
}
}
print(attributedString)
这里substringRange 是一个Range<String.Index>,它被转换为
对应NSRange与
NSRange(substringRange, in: text)