Les Stringgammes et NSStringgammes Swift ne sont pas "compatibles". Par exemple, un emoji comme 😄 compte pour un caractère Swift, mais comme deux NSString
caractères (une paire de substituts UTF-16).
Par conséquent, votre solution suggérée produira des résultats inattendus si la chaîne contient de tels caractères. Exemple:
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)
Production:
😄😄😄Long paragra {
} ph dis {
NSColor = "NSCalibratedRGBColorSpace 1 0 0 1";
} ing! {
}
Comme vous le voyez, "ph say" a été marqué avec l'attribut, pas "dire".
Étant donné que NS(Mutable)AttributedStringnécessite finalement un NSStringet un NSRange, il est en fait préférable de convertir la chaîne donnée en NSStringpremier. Ensuite, le substringRange
est un NSRangeet vous n'avez plus à convertir les plages:
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)
Production:
😄😄😄Long paragraphe {
}en disant{
NSColor = "NSCalibratedRGBColorSpace 1 0 0 1";
}! {
}
Mise à jour pour 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)
Mise à jour pour 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)
Mise à jour pour Swift 4:
Depuis Swift 4 (Xcode 9), la bibliothèque standard Swift fournit une méthode pour convertir entre Range<String.Index>et NSRange. La conversion en NSStringn'est plus nécessaire:
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)
Voici substringRangeun Range<String.Index>, et qui est converti en le correspondant NSRangeavec
NSRange(substringRange, in: text)