Wofür brauchen Sie die Reichweite? Schnelle Zeichenfolgen werden verwendet Range<String.Index>, aber manchmal ist es notwendig, mit NSStringund zu arbeiten NSRange, sodass etwas mehr Kontext nützlich wäre. - Schauen Sie sich aber stackoverflow.com/questions/24092884/… an .
Martin R
Antworten:
256
Aktualisiert für Swift 4
Swift-Bereiche sind komplexer als NSRangeund wurden in Swift 3 nicht einfacher. Wenn Sie versuchen möchten, die Gründe für diese Komplexität zu verstehen, lesen Sie dies und das . Ich zeige Ihnen nur, wie Sie sie erstellen und wann Sie sie verwenden könnten.
Geschlossene Bereiche: a...b
Dieser Bereichsoperator erstellt einen Swift-Bereich, der sowohl Element aals auch Element enthält b, auch wenn dies bder maximal mögliche Wert für einen Typ (wie Int.max) ist. Es gibt zwei verschiedene Arten von geschlossenen Bereichen: ClosedRangeund CountableClosedRange.
1. ClosedRange
Die Elemente aller Bereiche in Swift sind vergleichbar (dh sie entsprechen dem Comparable-Protokoll). Auf diese Weise können Sie aus einer Sammlung auf die Elemente im Bereich zugreifen. Hier ist ein Beispiel:
let myRange:ClosedRange=1...3let myArray =["a","b","c","d","e"]
myArray[myRange]//["b","c","d"]
A ClosedRangeist jedoch nicht zählbar (dh es entspricht nicht dem Sequenzprotokoll). Das heißt, Sie können die Elemente nicht mit einer forSchleife durchlaufen . Dafür brauchen Sie die CountableClosedRange.
2. CountableClosedRange
Dies ähnelt dem letzten, außer dass der Bereich jetzt auch wiederholt werden kann.
let myRange:CountableClosedRange=1...3let myArray =["a","b","c","d","e"]
myArray[myRange]// ["b", "c", "d"]
for index in myRange {
print(myArray[index])}
Halboffene Bereiche: a..<b
Dieser Bereichsoperator enthält ein Element, ajedoch kein Element b. Wie oben gibt es zwei verschiedene Arten von halboffenen Bereichen: Rangeund CountableRange.
1. Range
Wie bei ClosedRangekönnen Sie mit einem auf die Elemente einer Sammlung zugreifen Range. Beispiel:
let myRange:Range=1..<3let myArray =["a","b","c","d","e"]
myArray[myRange]//["b","c"]
Auch hier können Sie nicht über a iterieren, Rangeda es nur vergleichbar und nicht schrittfähig ist.
2. CountableRange
A CountableRangeermöglicht die Iteration.
let myRange:CountableRange=1..<3let myArray =["a","b","c","d","e"]
myArray[myRange]// ["b", "c"]
for index in myRange {
print(myArray[index])}
NSRange
Sie können (müssen) NSRangemanchmal noch in Swift verwenden ( z. B. wenn Sie zugeordnete Zeichenfolgen erstellen), daher ist es hilfreich zu wissen, wie man eine erstellt.
let myNSRange =NSRange(location:3, length:2)
Beachten Sie, dass dies Position und Länge ist , nicht Startindex und Endindex. Das Beispiel hier hat eine ähnliche Bedeutung wie der Swift-Bereich 3..<5. Da die Typen jedoch unterschiedlich sind, sind sie nicht austauschbar.
Bereiche mit Saiten
Die Operatoren ...und ..<range sind eine Kurzform zum Erstellen von Bereichen. Beispielsweise:
let myRange =1..<3
Der lange Weg, um den gleichen Bereich zu erstellen, wäre
let myRange =CountableRange<Int>(uncheckedBounds:(lower:1, upper:3))//1..<3
Sie können sehen, dass der Indextyp hier ist Int. Dies funktioniert jedoch nicht String, da Zeichenfolgen aus Zeichen bestehen und nicht alle Zeichen dieselbe Größe haben. (Lesen Sie dies für weitere Informationen.) Ein Emoji wie 😀 benötigt beispielsweise mehr Platz als der Buchstabe "b".
Problem mit NSRange
Versuchen Sie, mit NSRangeund NSStringmit Emoji zu experimentieren, und Sie werden sehen, was ich meine. Kopfschmerzen.
let myNSRange =NSRange(location:1, length:3)let myNSString:NSString="abcde"
myNSString.substring(with: myNSRange)// "bcd"
let myNSString2:NSString="a😀cde"
myNSString2.substring(with: myNSRange)//"😀c"Whereis the "d"!?
Das Smiley-Gesicht benötigt zwei UTF-16-Codeeinheiten zum Speichern, sodass das unerwartete Ergebnis entsteht, dass das "d" nicht enthalten ist.
Schnelle Lösung
Aus diesem Grund verwenden Sie Swift Strings Range<String.Index>nicht Range<Int>. Der String-Index wird basierend auf einem bestimmten String berechnet, damit er weiß, ob Emoji oder erweiterte Graphemcluster vorhanden sind.
In Swift 4 wurden die Dinge etwas vereinfacht. Wann immer der Start- oder Endpunkt eines Bereichs abgeleitet werden kann, können Sie ihn weglassen.
Int
Sie können einseitige Ganzzahlbereiche verwenden, um Sammlungen zu durchlaufen. Hier einige Beispiele aus der Dokumentation .
// iterate from index 2 to the end of the array
for name in names[2...]{
print(name)}// iterate from the beginning of the array to index 2
for name in names[...2]{
print(name)}// iterate from the beginning of the array up to but not including index 2
for name in names[..<2]{
print(name)}// the range from negative infinity to 5. You can't iterate forward
// over this because the starting point in unknown.
let range =...5
range.contains(7)// false
range.contains(4)// true
range.contains(-1)// true
// You can iterate over this but it will be an infinate loop
// so you have to break out at some point.
let range =5...
String
Dies funktioniert auch mit String-Bereichen. Wenn Sie einen Bereich mit str.startIndexoder str.endIndexan einem Ende erstellen, können Sie ihn weglassen. Der Compiler wird darauf schließen.
Gegeben
var str ="Hello, playground"let index = str.index(str.startIndex, offsetBy:5)let myRange =..<index //Hello
Sie können mithilfe von vom Index zum str.endIndex wechseln ...
var str ="Hello, playground"let index = str.index(str.endIndex, offsetBy:-10)let myRange = index...// playground
Sie können einen Bereich, den Sie mit einer Zeichenfolge erstellt haben, nicht für eine andere Zeichenfolge verwenden.
Wie Sie sehen können, sind String-Bereiche in Swift ein Problem, aber sie machen es möglicherweise möglich, besser mit Emoji und anderen Unicode-Skalaren umzugehen.
Mein Kommentar bezieht sich auf den Unterabschnitt "Problem mit NSRange". NSStringspeichert seine Zeichen intern in UTF-16-Codierung. Ein vollständiger Unicode-Skalar ist 21 Bit. Das grinsende Zeichen ( U+1F600) kann nicht in einer einzelnen 16-Bit-Codeeinheit gespeichert werden, daher ist es auf 2 NSRangeZählungen basierend auf 16-Bit-Codeeinheiten verteilt. In diesem Beispiel repräsentieren 3 Codeeinheiten zufällig nur 2 Zeichen
var start = str.startIndex // Start at the string's start index
var end = advance(str.startIndex,5)// Take start index and advance 5 characters forward
var range:Range<String.Index>=Range<String.Index>(start: start,end: end)let firstFiveDigit = str.substringWithRange(range)
print(firstFiveDigit)
Ich sehe, dass sie den Datentyp "Range" haben. Wie kann ich es verwenden?
Vichhai
@vichhai Können Sie näher erläutern, wo Sie verwenden möchten?
Dharmbir Singh
Wie in Ziel c: NSRange-Bereich;
Vichhai
1
Ich finde es überraschend, dass es selbst in Swift 4 noch keine einfache native Möglichkeit gibt, einen String-Bereich mit Int auszudrücken. Die einzigen String-Methoden, mit denen Sie ein Int angeben können, um einen Teilstring nach Bereich zu erhalten, sind prefixund suffix.
Es ist nützlich, einige Konvertierungsprogramme zur Hand zu haben, damit wir wie NSRange sprechen können, wenn wir mit einem String sprechen. Hier ist ein Dienstprogramm, das genau wie NSRange einen Speicherort und eine Länge annimmt und Folgendes zurückgibt Range<String.Index>:
Zum Beispiel "hello".range(0,1)"ist das Range<String.Index>Umarmen des ersten Charakters von "hello". Als Bonus habe ich auszuschließende Standorte erlaubt: "hello".range(-1,1)"die Range<String.Index>das letzte Zeichen umfassen "hello".
Es ist auch nützlich, a Range<String.Index>in einen NSRange zu konvertieren , wenn Sie mit Cocoa sprechen müssen (z. B. im Umgang mit NSAttributedString-Attributbereichen). Swift 4 bietet eine native Möglichkeit, dies zu tun:
let nsrange =NSRange(range,in:s)//where s is the string
Wir können also ein anderes Dienstprogramm schreiben, bei dem wir direkt von einem String-Speicherort und einer String-Länge zu einem NSRange wechseln:
let nsRange =NSRange(location: someInt, length: someInt)
wie in
let myNSString = bigTOTPCode asNSString//12345678
let firstDigit = myNSString.substringWithRange(NSRange(location:0, length:1))//1
let secondDigit = myNSString.substringWithRange(NSRange(location:1, length:1))//2
let thirdDigit = myNSString.substringWithRange(NSRange(location:2, length:4))//3456
Range<String.Index>
, aber manchmal ist es notwendig, mitNSString
und zu arbeitenNSRange
, sodass etwas mehr Kontext nützlich wäre. - Schauen Sie sich aber stackoverflow.com/questions/24092884/… an .Antworten:
Aktualisiert für Swift 4
Swift-Bereiche sind komplexer als
NSRange
und wurden in Swift 3 nicht einfacher. Wenn Sie versuchen möchten, die Gründe für diese Komplexität zu verstehen, lesen Sie dies und das . Ich zeige Ihnen nur, wie Sie sie erstellen und wann Sie sie verwenden könnten.Geschlossene Bereiche:
a...b
Dieser Bereichsoperator erstellt einen Swift-Bereich, der sowohl Element
a
als auch Element enthältb
, auch wenn diesb
der maximal mögliche Wert für einen Typ (wieInt.max
) ist. Es gibt zwei verschiedene Arten von geschlossenen Bereichen:ClosedRange
undCountableClosedRange
.1.
ClosedRange
Die Elemente aller Bereiche in Swift sind vergleichbar (dh sie entsprechen dem Comparable-Protokoll). Auf diese Weise können Sie aus einer Sammlung auf die Elemente im Bereich zugreifen. Hier ist ein Beispiel:
A
ClosedRange
ist jedoch nicht zählbar (dh es entspricht nicht dem Sequenzprotokoll). Das heißt, Sie können die Elemente nicht mit einerfor
Schleife durchlaufen . Dafür brauchen Sie dieCountableClosedRange
.2.
CountableClosedRange
Dies ähnelt dem letzten, außer dass der Bereich jetzt auch wiederholt werden kann.
Halboffene Bereiche:
a..<b
Dieser Bereichsoperator enthält ein Element,
a
jedoch kein Elementb
. Wie oben gibt es zwei verschiedene Arten von halboffenen Bereichen:Range
undCountableRange
.1.
Range
Wie bei
ClosedRange
können Sie mit einem auf die Elemente einer Sammlung zugreifenRange
. Beispiel:Auch hier können Sie nicht über a iterieren,
Range
da es nur vergleichbar und nicht schrittfähig ist.2.
CountableRange
A
CountableRange
ermöglicht die Iteration.NSRange
Sie können (müssen)
NSRange
manchmal noch in Swift verwenden ( z. B. wenn Sie zugeordnete Zeichenfolgen erstellen), daher ist es hilfreich zu wissen, wie man eine erstellt.Beachten Sie, dass dies Position und Länge ist , nicht Startindex und Endindex. Das Beispiel hier hat eine ähnliche Bedeutung wie der Swift-Bereich
3..<5
. Da die Typen jedoch unterschiedlich sind, sind sie nicht austauschbar.Bereiche mit Saiten
Die Operatoren
...
und..<
range sind eine Kurzform zum Erstellen von Bereichen. Beispielsweise:Der lange Weg, um den gleichen Bereich zu erstellen, wäre
Sie können sehen, dass der Indextyp hier ist
Int
. Dies funktioniert jedoch nichtString
, da Zeichenfolgen aus Zeichen bestehen und nicht alle Zeichen dieselbe Größe haben. (Lesen Sie dies für weitere Informationen.) Ein Emoji wie 😀 benötigt beispielsweise mehr Platz als der Buchstabe "b".Problem mit NSRange
Versuchen Sie, mit
NSRange
undNSString
mit Emoji zu experimentieren, und Sie werden sehen, was ich meine. Kopfschmerzen.Das Smiley-Gesicht benötigt zwei UTF-16-Codeeinheiten zum Speichern, sodass das unerwartete Ergebnis entsteht, dass das "d" nicht enthalten ist.
Schnelle Lösung
Aus diesem Grund verwenden Sie Swift Strings
Range<String.Index>
nichtRange<Int>
. Der String-Index wird basierend auf einem bestimmten String berechnet, damit er weiß, ob Emoji oder erweiterte Graphemcluster vorhanden sind.Beispiel
Einseitige Bereiche:
a...
und...b
und..<b
In Swift 4 wurden die Dinge etwas vereinfacht. Wann immer der Start- oder Endpunkt eines Bereichs abgeleitet werden kann, können Sie ihn weglassen.
Int
Sie können einseitige Ganzzahlbereiche verwenden, um Sammlungen zu durchlaufen. Hier einige Beispiele aus der Dokumentation .
String
Dies funktioniert auch mit String-Bereichen. Wenn Sie einen Bereich mit
str.startIndex
oderstr.endIndex
an einem Ende erstellen, können Sie ihn weglassen. Der Compiler wird darauf schließen.Gegeben
Sie können mithilfe von vom Index zum str.endIndex wechseln
...
Siehe auch:
Anmerkungen
Weitere Studie
quelle
NSString
speichert seine Zeichen intern in UTF-16-Codierung. Ein vollständiger Unicode-Skalar ist 21 Bit. Das grinsende Zeichen (U+1F600
) kann nicht in einer einzelnen 16-Bit-Codeeinheit gespeichert werden, daher ist es auf 2NSRange
Zählungen basierend auf 16-Bit-Codeeinheiten verteilt. In diesem Beispiel repräsentieren 3 Codeeinheiten zufällig nur 2 ZeichenXcode 8 Beta 2 • Swift 3
Xcode 7 • Swift 2.0
oder einfach
quelle
kehrt zurück...
quelle
Verwenden Sie so
Ausgabe: Hallo
quelle
Ich finde es überraschend, dass es selbst in Swift 4 noch keine einfache native Möglichkeit gibt, einen String-Bereich mit Int auszudrücken. Die einzigen String-Methoden, mit denen Sie ein Int angeben können, um einen Teilstring nach Bereich zu erhalten, sind
prefix
undsuffix
.Es ist nützlich, einige Konvertierungsprogramme zur Hand zu haben, damit wir wie NSRange sprechen können, wenn wir mit einem String sprechen. Hier ist ein Dienstprogramm, das genau wie NSRange einen Speicherort und eine Länge annimmt und Folgendes zurückgibt
Range<String.Index>
:Zum Beispiel
"hello".range(0,1)"
ist dasRange<String.Index>
Umarmen des ersten Charakters von"hello"
. Als Bonus habe ich auszuschließende Standorte erlaubt:"hello".range(-1,1)"
dieRange<String.Index>
das letzte Zeichen umfassen"hello"
.Es ist auch nützlich, a
Range<String.Index>
in einen NSRange zu konvertieren , wenn Sie mit Cocoa sprechen müssen (z. B. im Umgang mit NSAttributedString-Attributbereichen). Swift 4 bietet eine native Möglichkeit, dies zu tun:Wir können also ein anderes Dienstprogramm schreiben, bei dem wir direkt von einem String-Speicherort und einer String-Länge zu einem NSRange wechseln:
quelle
Wenn jemand ein NSRange-Objekt erstellen möchte, kann er Folgendes erstellen:
Dadurch wird ein Bereich mit Position 0 und Länge 5 erstellt
quelle
Ich habe die folgende Erweiterung erstellt:
Anwendungsbeispiel:
quelle
Sie können so verwenden
wie in
quelle
Ich möchte das machen:
Aber leider kann ich keinen eigenen Index schreiben, weil der Abscheuliche den Namensraum einnimmt.
Wir können dies jedoch tun:
Fügen Sie dies einfach Ihrem Projekt hinzu:
quelle
quelle