快速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)
输出:
para长paragra {
} ph说{
NSColor =“ NSCalibratedRGBColorSpace 1 0 0 1”;
} ing!{
}
如您所见,“ ph say”已被标记为属性,而不是“ saying”。
由于NS(Mutable)AttributedString
最终需要使用NSString
and和an NSRange
,因此最好将给定的字符串转换为NSString
first。然后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)
输出:
paragraph长款{
}说{
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)