Problem: NSAttributedString verwendet einen NSRange, während ich einen Swift-String verwende, der Range verwendet
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)
}
})
Erzeugt den folgenden Fehler:
Fehler: 'Range' kann nicht in 'NSRange' konvertiert werden. attributeString.addAttribute (NSForegroundColorAttributeName, Wert: NSColor.redColor (), Bereich: substringRange)
Antworten:
Schnelle
String
Bereiche undNSString
Bereiche sind nicht "kompatibel". Zum Beispiel zählt ein Emoji wie 😄 als ein Swift-Zeichen, aber als zweiNSString
Zeichen (ein sogenanntes UTF-16-Ersatzpaar).Daher führt Ihre vorgeschlagene Lösung zu unerwarteten Ergebnissen, wenn die Zeichenfolge solche Zeichen enthält. Beispiel:
Ausgabe:
Wie Sie sehen, wurde "ph say" mit dem Attribut markiert, nicht mit "say".
Da
NS(Mutable)AttributedString
letztendlich einNSString
und ein erforderlich istNSRange
, ist es tatsächlich besser, den angegebenen StringNSString
zuerst in einen zu konvertieren . DannsubstringRange
ist das einNSRange
und Sie müssen die Bereiche nicht mehr konvertieren:Ausgabe:
Update für Swift 2:
Update für Swift 3:
Update für Swift 4:
Ab Swift 4 (Xcode 9) bietet die Swift-Standardbibliothek eine Methode zum Konvertieren zwischen
Range<String.Index>
undNSRange
. Eine Umstellung aufNSString
ist nicht mehr erforderlich:Hier
substringRange
ist einRange<String.Index>
, und das wird in das entsprechendeNSRange
mit konvertiertquelle
Range<String.Index>
undNSString
sind nicht kompatibel. Sind ihre Gegenstücke auch nicht kompatibel? Dh sindNSRange
undString
inkompatibel? Denn eine von Apples API kombiniert speziell die beiden: Übereinstimmungen (in: Optionen: Bereich :)Für Fälle wie den von Ihnen beschriebenen habe ich festgestellt, dass dies funktioniert. Es ist relativ kurz und süß:
quelle
NSRange
.str
ist einNSString
und gibt daherstr.RangeOfString()
ein zurückNSRange
.let str = attributedString.string as NSString
Die Antworten sind in Ordnung, aber mit Swift 4 können Sie Ihren Code ein wenig vereinfachen:
Seien Sie vorsichtig, da das Ergebnis der
range
Funktion ausgepackt werden muss.quelle
Mögliche Lösung
Swift stellt distance () bereit, das den Abstand zwischen Start und Ende misst, mit dem ein NSRange erstellt werden kann:
quelle
Für mich funktioniert das perfekt:
quelle
Swift 4:
Klar, ich weiß, dass Swift 4 bereits eine Erweiterung für NSRange hat
Ich weiß, dass dieser Init in den meisten Fällen ausreicht. Siehe seine Verwendung:
Die Konvertierung kann jedoch direkt von Range <String.Index> nach NSRange ohne Swifts String-Instanz erfolgen.
Statt generic init Nutzung des von Ihnen das erfordert Zielparameter als String und wenn Sie nicht haben Ziel Zeichenfolge zur Hand können Sie Konvertierung direkt erstellen
oder Sie können die spezielle Erweiterung für Range selbst erstellen
Verwendung:
oder
Swift 5:
Aufgrund der standardmäßigen Migration von Swift-Zeichenfolgen zur UTF-8-Codierung wird die Verwendung von
encodedOffset
als veraltet betrachtet und Range kann ohne eine Instanz von String selbst nicht in NSRange konvertiert werden, da zur Berechnung des Offsets die Quellzeichenfolge erforderlich ist in UTF-8 codiert und sollte vor der Berechnung des Offsets in UTF-16 konvertiert werden. Der beste Ansatz ist daher, generisches Init zu verwenden .quelle
encodedOffset
wird als schädlich angesehen und veraltet sein .Swift 4
Ich denke, es gibt zwei Möglichkeiten.
1. NSRange (Bereich, in :)
2. NSRange (Ort:, Länge :)
Beispielcode:
Bildschirmfoto:
quelle
encodedOffset
wird als schädlich angesehen und veraltet sein .Swift 3-Erweiterungsvariante , die vorhandene Attribute beibehält.
quelle
quelle
Ich liebe die Swift-Sprache, aber die Verwendung
NSAttributedString
mit einem SwiftRange
, der nicht kompatibelNSRange
ist, hat meinen Kopf zu lange verletzt. Um all diesen Müll zu umgehen, habe ich die folgenden Methoden entwickelt, um eine zurückzugebenNSMutableAttributedString
mit den hervorgehobenen Wörtern zurückzugeben, die mit Ihrer Farbe festgelegt wurden.Dies funktioniert nicht für Emojis. Ändern Sie, wenn Sie müssen.
Verwendung:
quelle
quelle