Ich habe ein paar meiner alten Codes und Antworten mit Swift 3 aktualisiert, aber als ich zu Swift Strings und Indexing kam, war es ein Schmerz, Dinge zu verstehen.
Im Einzelnen habe ich folgendes versucht:
let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5) // error
wo die zweite Zeile mir den folgenden Fehler gab
'advancedBy' ist nicht verfügbar: Um einen Index um n Schritte vorzurücken, rufen Sie 'index (_: offsetBy :)' für die CharacterView-Instanz auf, die den Index erstellt hat.
Ich sehe, dass String
die folgenden Methoden hat.
str.index(after: String.Index)
str.index(before: String.Index)
str.index(String.Index, offsetBy: String.IndexDistance)
str.index(String.Index, offsetBy: String.IndexDistance, limitedBy: String.Index)
Das hat mich anfangs wirklich verwirrt, also habe ich angefangen, mit ihnen herumzuspielen, bis ich sie verstanden habe. Ich füge unten eine Antwort hinzu, um zu zeigen, wie sie verwendet werden.
Alle folgenden Beispiele verwenden
var str = "Hello, playground"
startIndex
und endIndex
startIndex
ist der Index des ersten ZeichensendIndex
ist der Index nach das letzte Zeichen.Beispiel
// character
str[str.startIndex] // H
str[str.endIndex] // error: after last character
// range
let range = str.startIndex..<str.endIndex
str[range] // "Hello, playground"
Mit Swift 4 einseitigen Bereichen kann der Bereich auf eine der folgenden Formen vereinfacht werden.
let range = str.startIndex...
let range = ..<str.endIndex
Ich werde das vollständige Formular in den folgenden Beispielen aus Gründen der Klarheit verwenden, aus Gründen der besseren Lesbarkeit sollten Sie jedoch wahrscheinlich die einseitigen Bereiche in Ihrem Code verwenden.
after
Wie in: index(after: String.Index)
after
bezieht sich auf den Index des Zeichens direkt nach dem angegebenen Index.Beispiele
// character
let index = str.index(after: str.startIndex)
str[index] // "e"
// range
let range = str.index(after: str.startIndex)..<str.endIndex
str[range] // "Ello, playground"
before
Wie in: index(before: String.Index)
before
bezieht sich auf den Index des Zeichens direkt vor dem angegebenen Index.Beispiele
// character
let index = str.index(before: str.endIndex)
str[index] // d
// range
let range = str.startIndex..<str.index(before: str.endIndex)
str[range] // Hello, playgroun
offsetBy
Wie in: index(String.Index, offsetBy: String.IndexDistance)
offsetBy
-Wert kann positiv oder negativ sein und beginnt am angegebenen Index. Obwohl es vom Typ String.IndexDistance
ist, können Sie ihm eine Int
geben.Beispiele
// character
let index = str.index(str.startIndex, offsetBy: 7)
str[index] // p
// range
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end
str[range] // play
limitedBy
Wie in: index(String.Index, offsetBy: String.IndexDistance, limitedBy: String.Index)
limitedBy
ist nützlich, um sicherzustellen, dass der Offset nicht dazu führt, dass sich der Index außerhalb der Grenzen befindet. Es ist ein Begrenzungsindex. Da es möglich ist, dass der Versatz den Grenzwert überschreitet, gibt diese Methode eine Option zurück. Es gibt nil
zurück, wenn der Index außerhalb der Grenzen liegt.Beispiel
// character
if let index = str.index(str.startIndex, offsetBy: 7, limitedBy: str.endIndex) {
str[index] // p
}
Wenn der Versatz 77
anstelle von 7
gewesen wäre, wäre die if
-Anweisung übersprungen worden.
Es wäre viel einfacher, einen Int
-Index für Strings zu verwenden. Der Grund dafür, dass Sie einen neuen String.Index
für jeden String erstellen müssen, ist, dass die Zeichen in Swift nicht alle unter der Haube gleich lang sind. Ein einzelnes Swift-Zeichen kann aus einem, zwei oder sogar mehr Unicode-Codepunkten bestehen. Daher muss jeder eindeutige String die Indizes seiner Zeichen berechnen.
Es ist möglich, diese Komplexität hinter einer Int-Indexerweiterung zu verbergen, aber ich zögere, dies zu tun. Es ist gut, daran erinnert zu werden, was tatsächlich passiert.
Ich stand vor dem gleichen Problem und bekam eine Lösung, die meinen Bedürfnissen entspricht. Ich habe eine UITextView in einem tableViewController. Ich verwendete die Funktion: textViewDidChange und überprüfte dann die Return-Key-Eingabe. Wenn dann die Return-Key-Eingabe erkannt wurde, löschte ich die Eingabe der Return-Taste und schloss die Tastatur ab.
func textViewDidChange(_ textView: UITextView) {
tableView.beginUpdates()
if textView.text.contains("\n"){
textView.text.remove(at: textView.text.index(before: textView.text.endIndex))
textView.resignFirstResponder()
}
tableView.endUpdates()
}