it-swarm.com.de

Ruft das n-te Zeichen einer Zeichenfolge in der Programmiersprache Swift ab

Wie kann ich das n-te Zeichen eines Strings erhalten? Ich habe es mit einem Bracket-Accessor ([]) ohne Glück versucht.

var string = "Hello, world!"

var firstChar = string[0] // Throws error

FEHLER: 'tiefgestellt' ist nicht verfügbar: Zeichenfolge mit Int kann nicht tiefgestellt werden. Weitere Informationen finden Sie im Dokumentationskommentar

381
Mohsen

Achtung: Eine korrekte Implementierung für Swift 4 finden Sie in Antwort von Leo Dabus .

Schnell 4

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

Probieren Sie es aus hier

extension String {
  subscript (i: Int) -> Character {
    return self[index(startIndex, offsetBy: i)]
  }
  subscript (bounds: CountableRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ..< end]
  }
  subscript (bounds: CountableClosedRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ... end]
  }
  subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(endIndex, offsetBy: -1)
    return self[start ... end]
  }
  subscript (bounds: PartialRangeThrough<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ... end]
  }
  subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ..< end]
  }
}
extension Substring {
  subscript (i: Int) -> Character {
    return self[index(startIndex, offsetBy: i)]
  }
  subscript (bounds: CountableRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ..< end]
  }
  subscript (bounds: CountableClosedRange<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[start ... end]
  }
  subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
    let start = index(startIndex, offsetBy: bounds.lowerBound)
    let end = index(endIndex, offsetBy: -1)
    return self[start ... end]
  }
  subscript (bounds: PartialRangeThrough<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ... end]
  }
  subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
    let end = index(startIndex, offsetBy: bounds.upperBound)
    return self[startIndex ..< end]
  }
}

Um Substring in String umzuwandeln, können Sie einfach String(string[0..2]) ausführen. Dies sollten Sie jedoch nur tun, wenn Sie vorhaben, die Teilzeichenfolge beizubehalten. Andernfalls ist es effizienter, es als Substring zu speichern.

Es wäre großartig, wenn jemand einen guten Weg finden könnte, diese beiden Erweiterungen zu einer zusammenzuführen. Ich habe erfolglos versucht, StringProtocol zu erweitern, da die Methode index dort nicht existiert.

Swift 3:

extension String {
  subscript (i: Int) -> Character {
    return self[index(startIndex, offsetBy: i)]
  }
  subscript (i: Int) -> String {
    return String(self[i] as Character)
  }
  subscript (r: Range<Int>) -> String {
    let start = index(startIndex, offsetBy: r.lowerBound)
    let end = index(startIndex, offsetBy: r.upperBound)
    return self[Range(start ..< end)]
  }
}

Warum ist das nicht eingebaut?

Apple liefert die folgende Erklärung ( hier zu finden ):

Das Abonnieren von Zeichenfolgen mit ganzen Zahlen ist nicht verfügbar.

Das Konzept des "ith-Zeichens in einer Zeichenfolge" wird in verschiedenen Bibliotheken und Systemkomponenten unterschiedlich interpretiert. Die richtige Interpretation sollte entsprechend dem Anwendungsfall und den beteiligten APIs ausgewählt werden, sodass String nicht mit einer Ganzzahl subskribiert werden kann.

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 konvertieren. Die meisten POSIX-APIs verarbeiten Zeichenfolgen in UTF-8-Codeeinheiten.

  • String.utf16 ist eine Sammlung von UTF-16-Codeeinheiten in Zeichenfolge. Die meisten Cocoa- und Cocoa-Touch-APIs verarbeiten Zeichenfolgen in UTF-16-Codeeinheiten. Beispielsweise speichern Instanzen von NSRange, die mit NSAttributedString und NSRegularExpression verwendet werden, Teilzeichenfolgen-Offsets und -Längen in UTF-16-Code-Einheiten.

  • String.unicodeScalars ist eine Sammlung von Unicode-Skalaren. Verwenden Sie diese API, wenn Sie auf niedriger Ebene Zeichendaten bearbeiten.

  • String.characters ist eine Sammlung erweiterter Graphemcluster, die eine Annäherung an vom Benutzer wahrgenommene Zeichen darstellen.

Beachten Sie, dass bei der Verarbeitung von Zeichenfolgen mit lesbarem Text die zeichenweise Verarbeitung so weit wie möglich vermieden werden sollte. Verwenden Sie stattdessen lokale Unicode-Algorithmen auf hoher Ebene, z. B. String.localizedStandardCompare(), String.localizedLowercaseString, String.localizedStandardRangeOfString() usw.

541
aleclarson

Swift 5 und früher

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

Sie müssen Ihrem Projekt diese String-Erweiterung hinzufügen (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<Int>) -> 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 dieses Problem immer sofort gelöst hat (ohne String-Erweiterung, die ich unten angegeben habe), würde ich dringend empfehlen die Erweiterung verwenden. Warum? Weil es mir zig Stunden schmerzhafter Migration von früheren Versionen von Swift erspart hat, in denen die Syntax von String fast bei jeder Veröffentlichung geändert wurde, war alles, was ich tun musste, die Implementierung der Erweiterung zu aktualisieren, anstatt das gesamte Projekt neu zu gestalten. Treffen Sie Ihre Wahl.

let str = "Hello, world!"
let index = str.index(str.startIndex, offsetBy: 4)
str[index] // returns Character 'o'

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

String(str.suffix(from: index)) // returns String "o, world!"
String(str.prefix(upTo: index)) // returns String "Hell"
310
NAlexN

Ich habe mir gerade diese nette Lösung ausgedacht

var firstChar = Array(string)[0]
129
Jens Wirth

Keine Indizierung mit ganzen Zahlen, nur mit String.Index. Meist mit linearer Komplexität. Sie können auch Bereiche aus String.Index erstellen und Teilzeichenfolgen daraus abrufen.

Swift 3.

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..<someString.index(someString.startIndex, offsetBy: 10)
let substring = someString[range]

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..<someString.startIndex.advanceBy(10)
let subtring = someString[range]

Beachten Sie, dass Sie niemals einen Index (oder Bereich) verwenden können, der von einer Zeichenfolge zu einer anderen Zeichenfolge erstellt wurde

let index10 = someString.startIndex.advanceBy(10)

//will compile
//sometimes it will work but sometimes it will crash or result in undefined behaviour
let charFromAnotherString = anotherString[index10]
122
Sulthan

Xcode 10.2 • Swift 5

Sie können StringProtocol erweitern, um den Index auch für die Teilzeichenfolgen verfügbar zu machen:

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

extension LosslessStringConvertible {
    var string: String { return .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]
    }
}

Testen

let test = "Hello USA ????????!!! Hello Brazil ????????!!!"
test[safe: 10]   // "????????"
test[11]   // "!"
test[10...]   // "????????!!! Hello Brazil ????????!!!"
test[10..<12]   // "????????!"
test[10...12]   // "????????!!"
test[...10]   // "Hello USA ????????"
test[..<10]   // "Hello USA "
test.first   // "H"
test.last    // "!"

// Subscripting the Substring
 test[...][...3]  // "Hell"

// Note that they all return a Substring of the original String.
// To create a new String you need to add .string as follow
test[10...].string  // "????????!!! Hello Brazil ????????!!!"
103
Leo Dabus

Schnell 4

let str = "My String"

String am Index

let index = str.index(str.startIndex, offsetBy: 3)
String(str[index])    // "S"

Teilzeichenfolge

let startIndex = str.index(str.startIndex, offsetBy: 3)
let endIndex = str.index(str.startIndex, offsetBy: 7)
String(str[startIndex...endIndex])     // "Strin"

Erste n Zeichen

let startIndex = str.index(str.startIndex, offsetBy: 3)
String(str[..<startIndex])    // "My "

Letzte n Zeichen

let startIndex = str.index(str.startIndex, offsetBy: 3)
String(str[startIndex...])    // "String"

Schnelle 2 und 3

str = "My String"

** String am Index **

Swift 2

let charAtIndex = String(str[str.startIndex.advancedBy(3)])  // charAtIndex = "S"

Schnell 3

str[str.index(str.startIndex, offsetBy: 3)]

Unterzeichenfolge von Index zu Index

Swift 2

let subStr = str[str.startIndex.advancedBy(3)...str.startIndex.advancedBy(7)] // subStr = "Strin"

Schnell 3

str[str.index(str.startIndex, offsetBy: 3)...str.index(str.startIndex, offsetBy: 7)]

Erste n Zeichen

let first2Chars = String(str.characters.prefix(2)) // first2Chars = "My"

Letzte n Zeichen

let last3Chars = String(str.characters.suffix(3)) // last3Chars = "ing"
59

Swift 2.0 ab Xcode 7 GM Seed

var text = "Hello, world!"

let firstChar = text[text.startIndex.advancedBy(0)] // "H"

Ersetzen Sie für das n-te Zeichen 0 durch n-1.

Edit: Swift 3.

text[text.index(text.startIndex, offsetBy: 0)]


n.b. Es gibt einfachere Möglichkeiten, bestimmte Zeichen in der Zeichenfolge zu erfassen

z.B. let firstChar = text.characters.first

24
Matt Le Fleur

Wenn Sie Cannot subscript a value of type 'String'... sehen, verwenden Sie diese Erweiterung:

Swift 3

extension String {
    subscript (i: Int) -> Character {
        return self[self.characters.index(self.startIndex, offsetBy: i)]
    }

    subscript (i: Int) -> String {
        return String(self[i] as Character)
    }

    subscript (r: Range<Int>) -> String {
        let start = index(startIndex, offsetBy: r.lowerBound)
        let end = index(startIndex, offsetBy: r.upperBound)
        return self[start..<end]
    }

    subscript (r: ClosedRange<Int>) -> String {
        let start = index(startIndex, offsetBy: r.lowerBound)
        let end = index(startIndex, offsetBy: r.upperBound)
        return self[start...end]
    }
}

Swift 2.3

extension String {
    subscript(integerIndex: Int) -> Character {
        let index = advance(startIndex, integerIndex)
        return self[index]
    }

    subscript(integerRange: Range<Int>) -> String {
        let start = advance(startIndex, integerRange.startIndex)
        let end = advance(startIndex, integerRange.endIndex)
        let range = start..<end
        return self[range]
    }
}

Quelle: http://oleb.net/blog/2014/07/Swift-strings/

23
SoftDesigner

Swift 2.2 Lösung:

Die folgende Erweiterung funktioniert in Xcode 7, dies ist eine Kombination aus this solution und Swift 2.0-Syntaxkonvertierung.

extension String {
    subscript(integerIndex: Int) -> Character {
        let index = startIndex.advancedBy(integerIndex)
        return self[index]
    }

    subscript(integerRange: Range<Int>) -> String {
        let start = startIndex.advancedBy(integerRange.startIndex)
        let end = startIndex.advancedBy(integerRange.endIndex)
        let range = start..<end
        return self[range]
    }
}
19
Dan Beaulieu

Swift 4

String(Array(stringToIndex)[index]) 

Dies ist wahrscheinlich der beste Weg, um dieses Problem einmal zu lösen. Sie möchten wahrscheinlich zuerst den String als Array und dann das Ergebnis erneut als String umwandeln. Andernfalls wird anstelle einer Zeichenfolge ein Zeichen zurückgegeben.

Beispiel String(Array("HelloThere")[1]) gibt "e" als String zurück.

(Array("HelloThere")[1] gibt "e" als Zeichen zurück.

Swift erlaubt es nicht, Strings wie Arrays zu indizieren, aber dies erledigt den Job im Brute-Force-Stil.

11
Harsh G.

Nebenbei bemerkt, gibt es einige Funktionen, die direkt auf die Darstellung einer Zeichenkette eines Strings angewendet werden können:

var string = "Hello, playground"
let firstCharacter = string.characters.first // returns "H"
let lastCharacter = string.characters.last // returns "d"

Das Ergebnis ist vom Typ Character, aber Sie können es in einen String umwandeln.

Oder dieses:

let reversedString = String(string.characters.reverse())
// returns "dnuorgyalp ,olleH" 

:-)

11
Frédéric Adda

Die Zeichenfolgenklasse Swift bietet aufgrund der systemeigenen Unterstützung von UTF-Zeichen keine Möglichkeit, Zeichen an einem bestimmten Index abzurufen. Die variable Länge eines UTF-Zeichens im Speicher macht es unmöglich, direkt zu einem Zeichen zu springen. Das bedeutet, dass Sie die Zeichenfolge jedes Mal manuell durchlaufen müssen.

Sie können String erweitern, um eine Methode bereitzustellen, die die Zeichen bis zum gewünschten Index durchläuft

extension String {
    func characterAtIndex(index: Int) -> Character? {
        var cur = 0
        for char in self {
            if cur == index {
                return char
            }
            cur++
        }
        return nil
    }
}

myString.characterAtIndex(0)!
11
drewag

Ich hatte gerade das gleiche Problem. Mach einfach das:

var aString: String = "test"
var aChar:unichar = (aString as NSString).characterAtIndex(0)
5
user3723247

Meine sehr einfache Lösung:

let myString = "Test string"
let index = 0
let firstCharacter = myString[String.Index(encodedOffset: index)]
4
Linh Dao

Swift3

Sie können die tiefgestellte Syntax verwenden, um an einem bestimmten String-Index auf das Zeichen zuzugreifen.

let greeting = "Guten Tag!"
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index] // a

Besuchen Sie https://developer.Apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html

oder wir können eine String Extension in Swift 4 machen

extension String {
    func getCharAtIndex(_ index: Int) -> Character {
        return self[self.index(self.startIndex, offsetBy: index)]
    }
}

VERWENDUNGSZWECK:

let foo = "ABC123"
foo.getCharAtIndex(2) //C
3
Hamed

Swift 3: eine andere Lösung (auf dem Spielplatz getestet)

extension String {
    func substr(_ start:Int, length:Int=0) -> String? {
        guard start > -1 else {
            return nil
        }

        let count = self.characters.count - 1

        guard start <= count else {
            return nil
        }

        let startOffset = max(0, start)
        let endOffset = length > 0 ? min(count, startOffset + length - 1) : count

        return self[self.index(self.startIndex, offsetBy: startOffset)...self.index(self.startIndex, offsetBy: endOffset)]
    }
}

Verwendungszweck:

let txt = "12345"

txt.substr(-1) //nil
txt.substr(0) //"12345"
txt.substr(0, length: 0) //"12345"
txt.substr(1) //"2345"
txt.substr(2) //"345"
txt.substr(3) //"45"
txt.substr(4) //"5"
txt.substr(6) //nil
txt.substr(0, length: 1) //"1"
txt.substr(1, length: 1) //"2"
txt.substr(2, length: 1) //"3"
txt.substr(3, length: 1) //"4"
txt.substr(3, length: 2) //"45"
txt.substr(3, length: 3) //"45"
txt.substr(4, length: 1) //"5"
txt.substr(4, length: 2) //"5"
txt.substr(5, length: 1) //nil
txt.substr(5, length: -1) //nil
txt.substr(-1, length: -1) //nil
3
Peter Kreinz

Meine Lösung ist in einer Zeile, angenommen, Cadena ist die Zeichenfolge und 4 ist die n-te Position, die Sie möchten:

let character = cadena[advance(cadena.startIndex, 4)]

Einfach ... Ich nehme an, Swift wird in zukünftigen Versionen weitere Informationen zu Teilzeichenfolgen enthalten.

Schnell 4

Bereichs- und Teilbereichssubskription mit der Eigenschaft String von indices

Als Variation von @ LeoDabus Nice answer können wir DefaultBidirectionalIndices um eine zusätzliche Erweiterung erweitern, um auf indices Eigenschaft von String beim Implementieren der benutzerdefinierten Indizes (durch Int spezialisierte Bereiche und Teilbereiche) für letztere.

extension DefaultBidirectionalIndices {
    subscript(at: Int) -> Elements.Index {
        return index(startIndex, offsetBy: at)
    }
}

// Moving the index(_:offsetBy:) to an extension yields slightly
// briefer implementations for these String extensions.
extension String {
    subscript(r: CountableClosedRange<Int>) -> SubSequence {
        return self[indices[r.lowerBound]...indices[r.upperBound]]
    }
    subscript(r: CountablePartialRangeFrom<Int>) -> SubSequence {
        return self[indices[r.lowerBound]...]
    }
    subscript(r: PartialRangeThrough<Int>) -> SubSequence {
        return self[...indices[r.upperBound]]
    }
    subscript(r: PartialRangeUpTo<Int>) -> SubSequence {
        return self[..<indices[r.upperBound]]
    }
}

let str = "foo bar baz bax"
print(str[4...6]) // "bar"
print(str[4...])  // "bar baz bax"
print(str[...6])  // "foo bar"
print(str[..<6])  // "foo ba"

Vielen Dank an @LeoDabus für den Hinweis auf die Verwendung der Eigenschaft indices als (andere) Alternative zur Subskription von String!

Swift 4.2.

In Swift 4.2, DefaultBidirectionalIndices wurde zugunsten von DefaultIndices verworfen.

2
dfri

Index abrufen und festlegen (Zeichenfolge und Teilzeichenfolge) - Swift 4.2

Swift 4.2, Xcode 10

Ich habe meine Antwort aus der Antwort von @ alecarlson abgeleitet. Der einzige große Unterschied ist, dass Sie ein Substring oder ein String zurückerhalten können (und in einigen Fällen ein einzelnes Character). Sie können auch get und set den Index eingeben. Schließlich ist meiner etwas umständlicher und länger als @alecarlson s Antwort und als solche schlage ich vor, dass Sie es in einer Quelldatei ablegen.


Erweiterung:

public extension String {
    public subscript (i: Int) -> Character {
        get {
            return self[index(startIndex, offsetBy: i)]
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
    public subscript (bounds: CountableRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ..< end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeThrough<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ... end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ..< end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }

    public subscript (i: Int) -> String {
        get {
            return "\(self[index(startIndex, offsetBy: i)])"
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            self.replaceSubrange(n...n, with: "\(c)")
        }
    }
    public subscript (bounds: CountableRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ..< end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeThrough<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ... end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ..< end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }

    public subscript (i: Int) -> Substring {
        get {
            return Substring("\(self[index(startIndex, offsetBy: i)])")
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
}
public extension Substring {
    public subscript (i: Int) -> Character {
        get {
            return self[index(startIndex, offsetBy: i)]
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }

    }
    public subscript (bounds: CountableRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ..< end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: PartialRangeThrough<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ... end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ..< end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }
    public subscript (i: Int) -> String {
        get {
            return "\(self[index(startIndex, offsetBy: i)])"
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
    public subscript (bounds: CountableRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ..< end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeThrough<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ... end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ..< end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }

    public subscript (i: Int) -> Substring {
        get {
            return Substring("\(self[index(startIndex, offsetBy: i)])")
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
}
2
Noah Wilder

Um das Thema zu füttern und die Möglichkeiten von Swift-Indizes anzuzeigen, ist hier ein kleiner String, der auf dem Index "substring-toolbox" basiert

Diese Methoden sind sicher und überschreiten niemals Zeichenfolgenindizes

extension String {
    // string[i] -> one string char
    subscript(pos: Int) -> String { return String(Array(self)[min(self.length-1,max(0,pos))]) }

    // string[pos,len] -> substring from pos for len chars on the left
    subscript(pos: Int, len: Int) -> String { return self[pos, len, .pos_len, .left2right] }

    // string[pos, len, .right2left] -> substring from pos for len chars on the right
    subscript(pos: Int, len: Int, way: Way) -> String { return self[pos, len, .pos_len, way] }

    // string[range] -> substring form start pos on the left to end pos on the right
    subscript(range: Range<Int>) -> String { return self[range.startIndex, range.endIndex, .start_end, .left2right] }

    // string[range, .right2left] -> substring start pos on the right to end pos on the left
    subscript(range: Range<Int>, way: Way) -> String { return self[range.startIndex, range.endIndex, .start_end, way] }

    var length: Int { return countElements(self) }
    enum Mode { case pos_len, start_end }
    enum Way { case left2right, right2left }
    subscript(var val1: Int, var val2: Int, mode: Mode, way: Way) -> String {
        if mode == .start_end {
            if val1 > val2 { let val=val1 ; val1=val2 ; val2=val }
            val2 = val2-val1
        }
        if way == .left2right {
            val1 = min(self.length-1, max(0,val1))
            val2 = min(self.length-val1, max(1,val2))
        } else {
            let val1_ = val1
            val1 = min(self.length-1, max(0, self.length-val1_-val2 ))
            val2 = max(1, (self.length-1-val1_)-(val1-1) )
        }
        return self.bridgeToObjectiveC().substringWithRange(NSMakeRange(val1, val2))

        //-- Alternative code without bridge --
        //var range: Range<Int> = pos...(pos+len-1)
        //var start = advance(startIndex, range.startIndex)
        //var end = advance(startIndex, range.endIndex)
        //return self.substringWithRange(Range(start: start, end: end))
    }
}


println("0123456789"[3]) // return "3"

println("0123456789"[3,2]) // return "34"

println("0123456789"[3,2,.right2left]) // return "56"

println("0123456789"[5,10,.pos_len,.left2right]) // return "56789"

println("0123456789"[8,120,.pos_len,.right2left]) // return "01"

println("0123456789"[120,120,.pos_len,.left2right]) // return "9"

println("0123456789"[0...4]) // return "01234"

println("0123456789"[0..4]) // return "0123"

println("0123456789"[0...4,.right2left]) // return "56789"

println("0123456789"[4...0,.right2left]) // return "678" << because ??? range can wear endIndex at 0 ???
2
Luc-Olivier

Swift 4.2

Diese Antwort ist ideal, weil sie String und alle ihre Subsequences (Substring) in einer Erweiterung erweitert

public extension StringProtocol {

    public subscript (i: Int) -> Element {
        return self[index(startIndex, offsetBy: i)]
    }

    public subscript (bounds: CountableClosedRange<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[start...end]
    }

    public subscript (bounds: CountableRange<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[start..<end]
    }

    public subscript (bounds: PartialRangeUpTo<Int>) -> SubSequence {
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[startIndex..<end]
    }

    public subscript (bounds: PartialRangeThrough<Int>) -> SubSequence {
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[startIndex...end]
    }

    public subscript (bounds: CountablePartialRangeFrom<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        return self[start..<endIndex]
    }
}

Verwendungszweck

var str = "Hello, playground"

print(str[5...][...5][0])
// Prints ","
2
Noah Wilder

Update für Swift 2.0 SubString

public extension String {
    public subscript (i: Int) -> String {
        return self.substringWithRange(self.startIndex..<self.startIndex.advancedBy(i + 1))
    }

    public subscript (r: Range<Int>) -> String {
        get {
            return self.substringWithRange(self.startIndex.advancedBy(r.startIndex)..<self.startIndex.advancedBy(r.endIndex))
        }
    }

}
2
YannSteph

In Swift

    let mystring = "Hello, world!"
    let stringToArray = Array(mystring.characters)

    let indices = (stringToArray.count)-1

    print(stringToArray[0]) //H
    print(stringToArray[indices]) //!
2
Rajamohan S

Swift 3

extension String {

    public func charAt(_ i: Int) -> Character {
        return self[self.characters.index(self.startIndex, offsetBy: i)]
    }

    public subscript (i: Int) -> String {
        return String(self.charAt(i) as Character)
    }

    public subscript (r: Range<Int>) -> String {
        return substring(with: self.characters.index(self.startIndex, offsetBy: r.lowerBound)..<self.characters.index(self.startIndex, offsetBy: r.upperBound))
    }

    public subscript (r: CountableClosedRange<Int>) -> String {
        return substring(with: self.characters.index(self.startIndex, offsetBy: r.lowerBound)..<self.characters.index(self.startIndex, offsetBy: r.upperBound))
    }

}

Verwendung

let str = "Hello World"
let sub = str[0...4]

Hilfreiche Tipps und Tricks zum Programmieren (von mir geschrieben)

2
quemeful

Ich denke, dass eine schnelle Antwort für das Erhalten des ersten Zeichens sein könnte:

let firstCharacter = aString[aString.startIndex]

Es ist so elegant und leistungsstark als:

let firstCharacter = Array(aString.characters).first

Aber wenn Sie mehr Operationen mit Strings ausführen möchten, können Sie sich vorstellen, eine Erweiterung zu erstellen. Bei diesem Ansatz gibt es eine Erweiterung, die der hier bereits beschriebenen sehr ähnlich ist:

extension String {
var length : Int {
    return self.characters.count
}

subscript(integerIndex: Int) -> Character {
    let index = startIndex.advancedBy(integerIndex)
    return self[index]
}

subscript(integerRange: Range<Int>) -> String {
    let start = startIndex.advancedBy(integerRange.startIndex)
    let end = startIndex.advancedBy(integerRange.endIndex)
    let range = start..<end
    return self[range]
}

}

ABER ES IST EINE SCHRECKLICHE IDEE !!

Die folgende Erweiterung ist schrecklich ineffizient. Bei jedem Zugriff auf eine Zeichenfolge mit einer Ganzzahl wird eine O(n) -Funktion ausgeführt, um den Startindex voranzutreiben. Wenn Sie eine lineare Schleife in einer anderen linearen Schleife ausführen, bedeutet dies, dass diese for-Schleife versehentlich O(n2) ist. Mit zunehmender Länge der Zeichenfolge nimmt die Zeit, die diese Schleife benötigt, quadratisch zu.

Stattdessen können Sie die Zeichenfolgensammlung der Zeichen verwenden.

2
ignaciohugog

Sie können String auch folgendermaßen in Array of Characters konvertieren:

let text = "My Text"
let index = 2
let charSequence = text.unicodeScalars.map{ Character($0) }
let char = charSequence[index]

Auf diese Weise können Sie char zu einem festgelegten Zeitpunkt am angegebenen Index abrufen.

Das folgende Beispiel wird nicht in konstanter Zeit ausgeführt, sondern erfordert eine lineare Zeit. Wenn Sie viel nach Index in String suchen, gehen Sie wie oben beschrieben vor.

let char = text[text.startIndex.advancedBy(index)]
1
Marcin Kapusta

Swifts String -Typ bietet keine characterAtIndex -Methode, da Unicode-Zeichenfolgen auf verschiedene Arten codiert werden können. Gehen Sie mit UTF8, UTF16 oder etwas anderem?

Sie können auf die Auflistungen CodeUnit zugreifen, indem Sie die Eigenschaften String.utf8 und String.utf16 abrufen. Sie können auch auf die Sammlung UnicodeScalar zugreifen, indem Sie die Eigenschaft String.unicodeScalars abrufen.

Im Sinne der Implementierung von NSString gebe ich den Typ unichar zurück.

extension String
{
    func characterAtIndex(index:Int) -> unichar
    {
        return self.utf16[index]
    }

    // Allows us to use String[index] notation
    subscript(index:Int) -> unichar
    {
        return characterAtIndex(index)
    }
}

let text = "Hello Swift!"
let firstChar = text[0]
1
Erik

In Swift 3 ohne Erweiterungen der String-Klasse, so einfach ich es machen kann!

let myString = "abcedfg"
let characterLocationIndex = myString.index(myString.startIndex, offsetBy: 3)
let myCharacter = myString[characterLocationIndex]

myCharacter ist in diesem Beispiel "3".

1
John Pavley

Die Verwendung von Zeichen würde den Job erledigen. Sie können den String schnell in ein Array von Zeichen konvertieren, das mit den CharacterView-Methoden bearbeitet werden kann.

Beispiel:

let myString = "Hello World!"
let myChars  = myString.characters

(full CharacterView doc)

(getestet in Swift 3)

1
Stephane Paquet

Es gibt eine Alternative, die in String-Manifest erklärt wird

extension String : BidirectionalCollection {
    subscript(i: Index) -> Character { return characters[i] }
}
1

Eine Python-ähnliche Lösung, mit der Sie einen negativen Index verwenden können.

var str = "Hello world!"
str[-1]        // "!"

könnte sein:

extension String {
    subscript (var index:Int)->Character{
        get {
            let n = distance(self.startIndex, self.endIndex)
            index %= n
            if index < 0 { index += n }
            return self[advance(startIndex, index)]
        }
    }
}

Übrigens kann es sich lohnen, die gesamte Python-Slice-Notation zu transponieren

1

Hier ist eine Erweiterung, die Sie verwenden können, um mit Swift 3.1 zu arbeiten. Ein einzelner Index gibt ein Character zurück, was beim Indizieren eines String intuitiv erscheint, und ein Range gibt ein String zurück.

extension String {
    subscript (i: Int) -> Character {
        return Array(self.characters)[i]
    }

    subscript (r: CountableClosedRange<Int>) -> String {
        return String(Array(self.characters)[r])
    }

    subscript (r: CountableRange<Int>) -> String {
        return self[r.lowerBound...r.upperBound-1]
    }
}

Einige Beispiele für die Erweiterung in Aktion:

let string = "Hello"

let c1 = string[1]  // Character "e"
let c2 = string[-1] // fatal error: Index out of range

let r1 = string[1..<4] // String "ell"
let r2 = string[1...4] // String "Ello"
let r3 = string[1...5] // fatal error: Array index is out of range



n.b. Sie können der obigen Erweiterung eine zusätzliche Methode hinzufügen, um String mit einem einzelnen Zeichen zurückzugeben, falls gewünscht:

subscript (i: Int) -> String {
    return String(self[i])
}

Beachten Sie, dass Sie dann den gewünschten Typ explizit angeben müssen, wenn Sie die Zeichenfolge indizieren:

let c: Character = string[3] // Character "l"
let s: String = string[0]    // String "H"
1
Matt Le Fleur

Überprüfen Sie, ob dies Swift 4 ist

let myString = "LOVE"

self.textField1.text = String(Array(myString)[0])
self.textField2.text = String(Array(myString)[1])
self.textField3.text = String(Array(myString)[2])
self.textField4.text = String(Array(myString)[3])
0
Sreekanth G

Ermöglicht negative Indizes

Es ist immer nützlich, nicht immer string[string.length - 1] schreiben zu müssen, um das letzte Zeichen zu erhalten, wenn eine tiefgestellte Erweiterung verwendet wird. Diese Erweiterung (Swift) ermöglicht negative Indizes, Range und CountableClosedRange.

extension String {
    var count: Int { return self.characters.count }

    subscript (i: Int) -> Character {
        // wraps out of bounds indices
        let j = i % self.count
        // wraps negative indices
        let x = j < 0 ? j + self.count : j

        // quick exit for first
        guard x != 0 else {
            return self.characters.first!
        }

        // quick exit for last
        guard x != count - 1 else {
            return self.characters.last!
        }

        return self[self.index(self.startIndex, offsetBy: x)]
    }

    subscript (r: Range<Int>) -> String {
        let lb = r.lowerBound
        let ub = r.upperBound

        // quick exit for one character
        guard lb != ub else { return String(self[lb]) }

        return self[self.index(self.startIndex, offsetBy: lb)..<self.index(self.startIndex, offsetBy: ub)]
    }

    subscript (r: CountableClosedRange<Int>) -> String {
        return self[r.lowerBound..<r.upperBound + 1]
    }
}

Wie können Sie es verwenden:

var text = "Hello World"

text[-1]    // d
text[2]     // l
text[12]    // e
text[0...4] // Hello
text[0..<4] // Hell

Für den gründlicheren Programmierer: Fügen Sie in diese Erweiterung ein guard gegen leere Strings ein

subscript (i: Int) -> Character {
    guard self.count != 0 else { return '' }
    ...
}

subscript (r: Range<Int>) -> String {
    guard self.count != 0 else { return "" }
    ...
}
0
Jay Harris

Fügen Sie diese Erweiterung in Ihr Projekt ein

  extension String{
func trim() -> String
{
    return self.trimmingCharacters(in: NSCharacterSet.whitespaces)
}

var length: Int {
    return self.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<Int>) -> 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])
}

func substring(fromIndex: Int, toIndex:Int)->String{
    let startIndex = self.index(self.startIndex, offsetBy: fromIndex)
    let endIndex = self.index(startIndex, offsetBy: toIndex-fromIndex)

    return String(self[startIndex...endIndex])
}

Verwenden Sie dann die Funktion wie folgt

let str = "Sample-String"

let substring = str.substring(fromIndex: 0, toIndex: 0) //returns S
let sampleSubstr = str.substring(fromIndex: 0, toIndex: 5) //returns Sample
0
AkilRajdho

Erhalte den ersten Buchstaben:

first(str) // retrieve first letter

Mehr hier: http://sketchytech.blogspot.com/2014/08/Swift-pure-Swift-method-for-returning.html

0
philippinedev

Swift 3:

extension String {
    func substring(fromPosition: UInt, toPosition: UInt) -> String? {
        guard fromPosition <= toPosition else {
            return nil
        }

        guard toPosition < UInt(characters.count) else {
            return nil
        }

        let start = index(startIndex, offsetBy: String.IndexDistance(fromPosition))
        let end   = index(startIndex, offsetBy: String.IndexDistance(toPosition) + 1)
        let range = start..<end

        return substring(with: range)
    }
}

"ffaabbcc".substring(fromPosition: 2, toPosition: 5) // return "aabb"
0
Daniele Ceglia

Verwenden Sie hierzu SwiftString ( https://github.com/amayne/SwiftString ).

"Hello, world!"[0] // H
"Hello, world!"[0...4] // Hello

HAFTUNGSAUSSCHLUSS: Ich habe diese Erweiterung geschrieben

0
eurobrew

Ich wollte darauf hinweisen, dass Sie, wenn Sie eine große Zeichenfolge haben und zufällig auf viele Zeichen zugreifen müssen, möglicherweise die zusätzlichen Speicherkosten bezahlen und die Zeichenfolge in ein Array konvertieren möchten, um eine bessere Leistung zu erzielen:

// Pay up front for O(N) memory
let chars = Array(veryLargeString.characters)

for i in 0...veryLargeNumber {
    // Benefit from O(1) access
    print(chars[i])
}
0
Joseph Chen