Problème: NSAttributedString prend un NSRange pendant que j'utilise une Swift String qui utilise Range
let text = "Long paragraph saying something goes here!"
let textRange = text.startIndex..<text.endIndex
let attributedString = NSMutableAttributedString(string: text)
text.enumerateSubstringsInRange(textRange, options: NSStringEnumerationOptions.ByWords, { (substring, substringRange, enclosingRange, stop) -> () in
if (substring == "saying") {
attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: substringRange)
}
})
Produit l'erreur suivante:
erreur: 'Range' n'est pas convertible en 'NSRange' attribuéString.addAttribute (NSForegroundColorAttributeName, value: NSColor.redColor (), range: substringRange)
Réponses:
Les
String
gammes etNSString
gammes Swift ne sont pas "compatibles". Par exemple, un emoji comme 😄 compte pour un caractère Swift, mais comme deuxNSString
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:
Production:
Comme vous le voyez, "ph say" a été marqué avec l'attribut, pas "dire".
Étant donné que
NS(Mutable)AttributedString
nécessite finalement unNSString
et unNSRange
, il est en fait préférable de convertir la chaîne donnée enNSString
premier. Ensuite, lesubstringRange
est unNSRange
et vous n'avez plus à convertir les plages:Production:
Mise à jour pour Swift 2:
Mise à jour pour Swift 3:
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>
etNSRange
. La conversion enNSString
n'est plus nécessaire:Voici
substringRange
unRange<String.Index>
, et qui est converti en le correspondantNSRange
avecla source
Range<String.Index>
etNSString
n'êtes pas compatible. Leurs homologues sont-ils également incompatibles? Ie sontNSRange
etString
incompatibles? Parce que l'une des API d'Apple combine spécifiquement les deux: matches (dans: options: range :)Pour des cas comme celui que vous avez décrit, j'ai trouvé que cela fonctionnait. C'est relativement court et doux:
la source
NSRange
.str
est unNSString
etstr.RangeOfString()
renvoie donc unNSRange
.let str = attributedString.string as NSString
Les réponses sont bonnes, mais avec Swift 4, vous pouvez simplifier un peu votre code:
Soyez prudent, car le résultat de la
range
fonction doit être déballé.la source
Solution possible
Swift fournit la distance () qui mesure la distance entre le début et la fin qui peut être utilisée pour créer un NSRange:
la source
Pour moi, cela fonctionne parfaitement:
la source
Swift 4:
Bien sûr, je sais que Swift 4 a déjà une extension pour NSRange
Je sais que dans la plupart des cas, cette init est suffisante. Voir son utilisation:
Mais la conversion peut être effectuée directement de Range <String.Index> à NSRange sans l'instance String de Swift.
Au lieu d'une utilisation d' initialisation générique qui nécessite de votre part le paramètre cible en tant que chaîne et si vous n'avez pas de chaîne cible à portée de main, vous pouvez créer une conversion directement
ou vous pouvez créer l'extension spécialisée pour Range lui-même
Usage:
ou
Swift 5:
En raison de la migration des chaînes Swift vers le codage UTF-8 par défaut, l'utilisation de
encodedOffset
est considérée comme obsolète et Range ne peut pas être converti en NSRange sans une instance de String elle-même, car pour calculer le décalage, nous avons besoin de la chaîne source qui est encodé en UTF-8 et il doit être converti en UTF-16 avant de calculer le décalage. La meilleure approche, pour l'instant, est donc d'utiliser init générique .la source
encodedOffset
est considérée comme nuisible et sera obsolète .Swift 4
Je pense qu'il y a deux façons.
1. NSRange (plage, en:)
2. NSRange (emplacement :, longueur:)
Exemple de code:
Capture d'écran:
la source
encodedOffset
est considérée comme nuisible et sera obsolète .Variante d'extension Swift 3 qui préserve les attributs existants.
la source
la source
J'adore le langage Swift, mais l'utiliser
NSAttributedString
avec un SwiftRange
qui n'est pas compatible avecNSRange
m'a fait mal à la tête pendant trop longtemps. Donc, pour contourner toutes ces ordures, j'ai conçu les méthodes suivantes pour renvoyer unNSMutableAttributedString
avec les mots en surbrillance définis avec votre couleur.Cela ne fonctionne pas pour les emojis. Modifiez si vous le devez.
Usage:
la source
la source