StringPhạm vi và phạm vi Swift NSStringkhông "tương thích". Ví dụ: một biểu tượng cảm xúc như 😄 được tính là một ký tự Swift, nhưng là hai NSString
ký tự (một cặp được gọi là cặp thay thế UTF-16).
Do đó, giải pháp được đề xuất của bạn sẽ tạo ra kết quả không mong muốn nếu chuỗi chứa các ký tự đó. Thí dụ:
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)
Đầu ra:
ParLong paragra {
} ph nói {
NSColor = "NSCalibratedRGBColorSpace 1 0 0 1";
} ing! {
}
Như bạn thấy, "ph say" đã được đánh dấu bằng thuộc tính, không phải "nói".
Vì NS(Mutable)AttributedStringcuối cùng đòi hỏi một NSStringvà một NSRange, nên thực sự tốt hơn để chuyển đổi chuỗi đã cho thành NSStringđầu tiên. Sau đó, substringRange
là một NSRangevà bạn không phải chuyển đổi phạm vi nữa:
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)
Đầu ra:
Đoạn văn dài {
} nói {
NSColor = "NSCalibratedRGBColorSpace 1 0 0 1";
}! {
}
Cập nhật cho 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)
Cập nhật cho 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)
Cập nhật cho Swift 4:
Kể từ Swift 4 (Xcode 9), thư viện chuẩn Swift cung cấp phương thức để chuyển đổi giữa Range<String.Index>và NSRange. Chuyển đổi sang NSStringkhông còn cần thiết:
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)
Đây substringRangelà một Range<String.Index>, và được chuyển đổi thành tương ứng NSRangevới
NSRange(substringRange, in: text)