513 Stimmen

Erhalten Sie das n-te Zeichen eines Strings in Swift

Wie kann ich das n-te Zeichen einer Zeichenkette erhalten? Ich habe es mit dem eckigen Klammern ([]) Operator versucht, aber es hat nicht geklappt.

var string = "Hallo, Welt!"

var firstChar = string[0] // Wirft einen Fehler

FEHLER: 'subscript' ist nicht verfügbar: String kann nicht mit einem Int indiziert werden, siehe den Dokumentationskommentar für weitere Informationen

612voto

aleclarson Punkte 17107

Achtung: Bitte siehe Leo Dabus' Antwort für eine korrekte Implementierung für Swift 4 und Swift 5.

Swift 4 oder neuer

Der Typ Substring wurde in Swift 4 eingeführt, um Teilzeichenfolgen schneller und effizienter zu machen, indem der Speicher mit der ursprünglichen Zeichenfolge gemeinsam genutzt wird, so dass die Indexfunktionen das zurückgeben sollten.

Probieren Sie es hier aus

extension StringProtocol {
    subscript(offset: Int) -> Character { self[index(startIndex, offsetBy: offset)] }
    subscript(range: Range) -> SubSequence {
        let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
        return self[startIndex..) -> SubSequence {
        let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
        return self[startIndex..) -> SubSequence { self[index(startIndex, offsetBy: range.lowerBound)...] }
    subscript(range: PartialRangeThrough) -> SubSequence { self[...index(startIndex, offsetBy: range.upperBound)] }
    subscript(range: PartialRangeUpTo) -> SubSequence { self[..

``

Um den Substring in einen String umzuwandeln, können Sie einfach String(string[0..2]) verwenden, sollten dies aber nur tun, wenn Sie die Teilzeichenfolge behalten möchten. Andernfalls ist es effizienter, es als Substring zu belassen.

Es wäre großartig, wenn jemand einen guten Weg finden könnte, diese beiden Erweiterungen in einer zu vereinen. Ich habe versucht, StringProtocol zu erweitern, jedoch ohne Erfolg, da die index-Methode dort nicht existiert. Hinweis: Diese Antwort wurde bereits bearbeitet, ist ordnungsgemäß implementiert und funktioniert jetzt auch für Teilzeichenfolgen. Stellen Sie einfach sicher, dass Sie einen gültigen Bereich verwenden, um Abstürze bei der Indizierung Ihres StringProtocol-Typs zu vermeiden. Für die Indizierung mit einem Bereich, der nicht mit Werten außerhalb des Bereichs abstürzt, können Sie diese Implementierung verwenden


Warum ist dies nicht eingebaut?

Die Fehlermeldung sagt "siehe die Dokumentationskommentare für die Diskussion". Apple liefert in der Datei UnavailableStringAPIs.swift folgende Erklärung:

Das Indizierung von Strings mit ganzen Zahlen ist nicht verfügbar.

Das Konzept des "i-ten Zeichens in einem String" hat in verschiedenen Bibliotheken und Systemkomponenten unterschiedliche Interpretationen. Die richtige Interpretation sollte je nach Anwendungsfall und den beteiligten APIs ausgewählt werden, daher kann die Indizierung von String mit einer ganzen Zahl nicht erfolgen.

Swift bietet verschiedene Möglichkeiten, auf die in Strings gespeicherten Zeichendaten zuzugreifen.

  • String.utf8 ist eine Sammlung von UTF-8-Codeeinheiten in der Zeichenfolge. Verwenden Sie diese API, wenn Sie die Zeichenfolge in UTF-8 umwandeln. Die meisten POSIX-APIs verarbeiten Zeichenfolgen von UTF-8-Codeeinheiten.

  • String.utf16 ist eine Sammlung von UTF-16-Codeeinheiten in der Zeichenfolge. Die meisten Cocoa- und Cocoa-Touch-APIs verarbeiten Zeichenfolgen von UTF-16-Codeeinheiten. Zum Beispiel verwenden Instanzen von NSRange verwendet mit NSAttributedString und NSRegularExpression speichern Unterzeichenfolgenoffsets und -längen in Form von UTF-16-Codeeinheiten.

  • String.unicodeScalars ist eine Sammlung von Unicode-Scalars. Verwenden Sie diese API, wenn Sie eine Low-Level-Manipulation der Zeichendaten durchführen.

  • String.characters ist eine Sammlung von erweiterten Graphemclustern, die eine Näherung an vom Benutzer wahrgenommene Zeichen sind.

Beachten Sie, dass bei der Verarbeitung von Zeichenfolgen mit menschenlesbarem Text die zeichenweise Verarbeitung möglichst vermieden werden sollte. Verwenden Sie stattdessen hochrangige, ortsabhängige Unicode-Algorithmen, zum Beispiel, String.localizedStandardCompare(), String.localizedLowercaseString, String.localizedStandardRangeOfString() usw.

``

440voto

nalexn Punkte 9983

Swift 5.2

let str = "abcdef"
str[1 ..< 3] // gibt "bc" zurück
str[5] // gibt "f" zurück
str[80] // gibt "" zurück
str.substring(fromIndex: 3) // gibt "def" zurück
str.substring(toIndex: str.length - 2) // gibt "abcd" zurück

Sie müssen diese String-Erweiterung zu Ihrem Projekt hinzufügen (sie ist vollständig getestet):

extension String {

    var length: Int {
        return count
    }

    subscript (i: Int) -> String {
        return self[i ..< i + 1]
    }

    func substring(fromIndex: Int) -> String {
        return self[min(fromIndex, length) ..< length]
    }

    func substring(toIndex: Int) -> String {
        return self[0 ..< max(0, toIndex)]
    }

    subscript (r: Range) -> String {
        let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
                                            upper: min(length, max(0, r.upperBound))))
        let start = index(startIndex, offsetBy: range.lowerBound)
        let end = index(start, offsetBy: range.upperBound - range.lowerBound)
        return String(self[start ..< end])
    }
}

Auch wenn Swift immer eine Lösung für dieses Problem (ohne String-Erweiterung, die ich unten bereitgestellt habe) hatte, empfehle ich dringend, die Erweiterung zu verwenden. Warum? Weil es mich vor stundenlanger schmerzhafter Migration von frühen Swift-Versionen gerettet hat, in denen die Syntax von String sich fast bei jedem Release änderte, ich aber nur die Implementierung der Erweiterung aktualisieren musste, anstatt das gesamte Projekt umzuarbeiten. Treffen Sie Ihre Wahl.

let str = "Hallo, Welt!"
let index = str.index(str.startIndex, offsetBy: 4)
str[index] // gibt Zeichen 'o' zurück

let endIndex = str.index(str.endIndex, offsetBy:-2)
str[index ..< endIndex] // gibt String "o, worl" zurück

String(str.suffix(from: index)) // gibt String "o, world!" zurück
String(str.prefix(upTo: index)) // gibt String "Hell" zurück

187voto

Jens Wirth Punkte 16422

Ich habe gerade diese clevere Lösung gefunden

var firstChar = Array(string)[0]

166voto

Leo Dabus Punkte 215103

Xcode 11 • Swift 5.1

Sie können StringProtocol erweitern, um den Indexoperator auch für Teilstrings verfügbar zu machen:

extension StringProtocol {
    subscript(_ offset: Int)                     -> Element     { self[index(startIndex, offsetBy: offset)] }
    subscript(_ range: Range)               -> SubSequence { prefix(range.lowerBound+range.count).suffix(range.count) }
    subscript(_ range: ClosedRange)         -> SubSequence { prefix(range.lowerBound+range.count).suffix(range.count) }
    subscript(_ range: PartialRangeThrough) -> SubSequence { prefix(range.upperBound.advanced(by: 1)) }
    subscript(_ range: PartialRangeUpTo)    -> SubSequence { prefix(range.upperBound) }
    subscript(_ range: PartialRangeFrom)    -> SubSequence { suffix(Swift.max(0, count-range.lowerBound)) }
}

extension LosslessStringConvertible {
    var string: String { .init(self) }
}

extension BidirectionalCollection {
    subscript(safe offset: Int) -> Element? {
        guard !isEmpty, let i = index(startIndex, offsetBy: offset, limitedBy: index(before: endIndex)) else { return nil }
        return self[i]
    }
}

Testing

let test = "Hallo USA !!! Hallo Brasilien !!!"
test[safe: 10]   // ""
test[11]   // "!"
test[10...]   // "!!! Hallo Brasilien !!!"
test[10..<12]   // "!"
test[10...12]   // "!!"
test[...10]   // "Hallo USA "
test[..<10]   // "Hallo USA "
test.first   // "H"
test.last    // "!"

// Teilstrings indizieren
 test[...][...3]  // "Hell"

// Beachten Sie, dass sie alle einen Teilstring des ursprünglichen Strings zurückgeben.
// Um einen neuen String aus einem Teilstring zu erstellen
test[10...].string  // "!!! Hallo Brasilien !!!"

134voto

Sulthan Punkte 123129

Kein Indexieren mit Ganzzahlen, nur mit String.Index. Meistens mit linearer Komplexität. Sie können auch Bereiche von String.Index erstellen und Teilzeichenfolgen damit abrufen.

Swift 3.0

let firstChar = someString[someString.startIndex]
let lastChar = someString[someString.index(before: someString.endIndex)]
let charAtIndex = someString[someString.index(someString.startIndex, offsetBy: 10)]

let range = someString.startIndex..

``Swift 2.x

let firstChar = someString[someString.startIndex]
let lastChar = someString[someString.endIndex.predecessor()]
let charAtIndex = someString[someString.startIndex.advanceBy(10)]

let range = someString.startIndex..

`Beachten Sie, dass Sie einen Index (oder Bereich), der aus einer Zeichenkette erstellt wurde, niemals auf eine andere Zeichenkette anwenden können

let index10 = someString.startIndex.advanceBy(10)

//wird kompilieren
//manchmal funktioniert es, aber manchmal stürzt es ab oder führt zu undefiniertem Verhalten
let charFromAnotherString = anotherString[index10]` ``

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X