String
Phạm vi và phạm vi Swift NSString
khô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)AttributedString
cuối cùng đòi hỏi một NSString
và 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 NSRange
và 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 NSString
khô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 substringRange
là một Range<String.Index>
, và được chuyển đổi thành tương ứng NSRange
với
NSRange(substringRange, in: text)