Récupère le nième caractère d'une chaîne dans le langage de programmation Swift

Comment puis-je obtenir le nième caractère d'une chaîne? J'ai essayé support ([]) accesseur sans chance.

var string = "Hello, world!"

var firstChar = string[0] // Throws error
323
demandé sur Vadim Kotov 2014-06-07 05:50:31

30 réponses

Attention: veuillez consulter la réponse de Leo dabus pour une implémentation correcte pour Swift 4.

Swift 4

Le type Substring a été introduit dans Swift 4 pour créer des sous-chaînes plus rapide et plus efficace en partageant le stockage avec la chaîne d'origine, c'est donc ce que les fonctions d'indice devraient retourner.

Essayez-le ici

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]
  }
}

Pour convertir les Substring en String, vous pouvez simplement faites String(string[0..2]), mais vous ne devriez le faire que si vous envisagez d' garder la sous-chaîne autour de. Sinon, c'est plus efficace pour le garder un Substring.

Ce serait génial si quelqu'un pouvait trouver un bon moyen de fusionner ces deux extensions en une seule. J'ai essayé d'étendre StringProtocol sans succès, car la méthode index n'existe pas là.

 

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)]
  }
}

 

Pourquoi ce n'est pas intégré?

Apple fournit l'explication suivante (trouvés ici):

Chaînes D'inscription avec des entiers n'est pas disponible.

Le concept de "le i e caractère dans une chaîne" a différentes interprétations dans différentes bibliothèques et systèmes composant. L'interprétation correcte doit être sélectionné selon le cas d'utilisation et les API impliquées, donc String ne peut pas être subscrit avec un entier.

Swift offre plusieurs façons d'accéder au personnage données stockées dans les chaînes.

  • String.utf8 est une collection D'UTF-8 unités de code dans le chaîne. Utilisez cette API lors de la conversion de la chaîne en UTF-8. La plupart des API POSIX traitent des chaînes en termes D'unités de code UTF-8.

  • String.utf16 est une collection D'unités de code UTF-16 dans chaîne. La plupart des API Cocoa et Cocoa touch traitent les chaînes termes des unités de code UTF-16. Par exemple, en cas de NSRange utilisé avec NSAttributedString et NSRegularExpression stocke les décalages et les longueurs de sous-chaîne dans termes des unités de code UTF-16.

  • String.unicodeScalars est une collection de Scalaires Unicode. Utilisez cette API lorsque vous effectuez une manipulation de bas niveau des données de caractère.

  • String.characters est une collection de l'étendue de graphème clusters, qui sont une approximation de l'utilisateur perçu caractère.

Notez que lors du traitement de chaînes contenant du texte lisible par l'homme, le traitement caractère par caractère doit être évité dans la plus grande mesure possible. Utilisez plutôt des algorithmes Unicode sensibles aux paramètres régionaux, par exemple, String.localizedStandardCompare(), String.localizedLowercaseString, String.localizedStandardRangeOfString() etc.

485
répondu aleclarson 2018-08-31 13:01:16

Chaîne prend en charge indice (accès avec [ ] ) hors de la boîte:

Swift 4

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"

En utilisant vos propres extensions, vous pouvez utiliser une syntaxe plus concise:

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"

... votre extension de chaîne devrait être comme (entièrement testé):

extension String {

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

}
286
répondu NAlexN 2018-04-26 13:30:01

Pas d'indexation en utilisant des entiers, seulement en utilisant String.Index. Surtout avec une complexité linéaire. Vous pouvez également créer des plages à partir de String.Index et obtenir des sous-chaînes en les utilisant.

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..<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]

Notez que vous ne pouvez jamais utiliser un index (ou une plage) créé d'une chaîne à une autre chaîne

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
répondu Sulthan 2017-06-24 05:27:57

Je viens de trouver cette solution de contournement soignée

var firstChar = Array(string)[0]
109
répondu Jens Wirth 2014-06-12 06:58:43

Swift 4.1 ou une version ultérieure

Vous pouvez étendre Stringprotocol de Swift 4 pour rendre l'indice disponible également aux sous-chaînes. Note: En raison de la Proposition SE-0191 l'extension contrainte à IndexDistance == Int peut être supprimée:

extension StringProtocol {

    var string: String { return String(self) }

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

    subscript(_ range: CountableRange<Int>) -> SubSequence {
        return prefix(range.lowerBound + range.count)
            .suffix(range.count)
    }
    subscript(range: CountableClosedRange<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 Substring {
    var string: String { return String(self) }
}    

Test

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 !!!"
75
répondu Leo Dabus 2018-09-04 22:51:45

Swift 4

let str = "My String"

Chaîne à index

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

Sous-Chaîne

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

N Premiers caractères

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

N Derniers caractères

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

Swift 2 et 3

str = "My String"

* * Chaîne À L'Index * *

Swift 2

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

Swift 3

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

sous-Chaîne fromIndex toIndex

Swift 2

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

Swift 3

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

Première n caractères

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

n Derniers caractères

let last3Chars = String(str.characters.suffix(3)) // last3Chars = "ing"
47
répondu Warif Akhand Rishi 2017-11-08 12:03:03

Swift 2.0 à partir de Xcode 7 GM Seed

var text = "Hello, world!"

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

Pour le nième caractère, remplacez 0 par n-1.

Modifier: Swift 3.0

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


N. B. Il existe des moyens plus simples de saisir certains caractères dans la chaîne

Par exemple let firstChar = text.characters.first

24
répondu Matt Le Fleur 2016-09-23 13:28:12

Si vous voyez Cannot subscript a value of type 'String'... utiliser cette extension:

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]
    }
}

Source: http://oleb.net/blog/2014/07/swift-strings/

23
répondu SoftDesigner 2016-11-16 17:44:11

Solution Swift 2.2:

L'extension suivante fonctionne dans Xcode 7, c'est une combinaison de Cette solution et la conversion de syntaxe Swift 2.0.

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
répondu Dan Beaulieu 2016-05-22 14:36:20

La classe swift string ne permet pas d'obtenir un caractère à un index spécifique en raison de sa prise en charge native des caractères UTF. La longueur variable D'un caractère UTF en mémoire rend le saut directement à un caractère impossible. Cela signifie que vous devez faire une boucle manuellement sur la chaîne à chaque fois.

Vous pouvez étendre String pour fournir une méthode qui parcourra les caractères jusqu'à ce que votre index désiré

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
répondu drewag 2014-06-12 14:23:54

Comme note de côté, il y a quelques fonctions directement applicables à la représentation de la chaîne de caractères d'une chaîne, comme ceci:

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

Le résultat est de type Character, mais vous pouvez le convertir en chaîne.

Ou ceci:

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

:-)

11
répondu Frédéric Adda 2015-11-07 15:56:17

Swift 4

String(Array(stringToIndex)[index]) 

C'est probablement la meilleure façon de résoudre ce problème une fois. Vous voulez probablement lancer la chaîne en tant que tableau d'abord, puis lancer le résultat en tant que chaîne à nouveau. Sinon, un caractère sera renvoyé au lieu d'une chaîne.

Exemple {[1] } renverra "e" sous forme de chaîne.

(Array("HelloThere")[1] retournera "e" en tant que personnage.

Swift ne permet pas aux chaînes d'être indexées comme des tableaux, mais cela fait le travail, style force brute.

7
répondu Harsh G. 2017-11-10 19:42:00

J'ai juste eu le même problème. Faites simplement ceci:

var aString: String = "test"
var aChar:unichar = (aString as NSString).characterAtIndex(0)
5
répondu user3723247 2015-08-04 19:37:51

Ma solution est dans une ligne, en supposant que cadena est la chaîne et 4 est la nième position que vous voulez:

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

Simple... Je suppose que Swift inclura plus de choses sur les sous-chaînes dans les futures versions.

3
répondu Julio César Fernández Muñoz 2014-08-09 23:29:44

Ma solution très simple:

let myString = "Test string"
let index = 0
let firstCharacter = myString[String.Index(encodedOffset: index)]
3
répondu Linh Dao 2018-03-02 04:13:15

Afin d'alimenter le sujet et de montrer les possibilités d'indice swift, voici une petite chaîne "substring-toolbox" en indice

Ces méthodes sont sûres et ne passent jamais sur les index de chaînes

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
répondu Luc-Olivier 2014-07-02 12:37:30

Mise à jour pour la sous-chaîne swift 2.0

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
répondu YannickSteph 2015-09-14 16:38:50

Je pense qu'une réponse rapide pour obtenir le premier personnage pourrait être:

let firstCharacter = aString[aString.startIndex]

C'est tellement élégant et performant que:

let firstCharacter = Array(aString.characters).first

Mais.. si vous voulez manipuler et faire plus d'opérations avec des chaînes, vous pouvez penser à créer une extension..voici une extension avec cette approche, c'est assez similaire à celle déjà affichée ici:

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]
}

}

MAIS C'EST UNE IDÉE TERRIBLE!!

L'extension ci-dessous est horriblement inefficace. Chaque fois qu'une chaîne est accessible avec un entier, une fonction O(N) pour faire avancer son index de départ est exécutée. Exécuter une boucle linéaire dans une autre boucle linéaire signifie que cette boucle for Est accidentellement O (n2) - à mesure que la longueur de la chaîne augmente, le temps que prend cette boucle augmente quadratiquement.

Au lieu de faire cela, vous pouvez utiliser la collection de chaînes des caractères.

2
répondu ignaciohugog 2016-06-18 17:19:14

Dans Swift 3

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

    let indices = (stringToArray.count)-1

    print(stringToArray[0]) //H
    print(stringToArray[indices]) //!
2
répondu Rajamohan S 2016-10-19 07:25:13

Swift 3: une autre solution (testé dans l'aire de jeux)

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)]
    }
}

Utilisation:

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
2
répondu Peter Kreinz 2017-04-11 22:13:47

Swift3

Vous pouvez utiliser la syntaxe d'indice pour accéder au caractère à un index de chaîne particulier.

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

Visite https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html

Ou nous pouvons faire une Extension de chaîne dans Swift 4

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

Utilisation:

let foo = "ABC123"
foo.getCharAtIndex(2) //C
2
répondu Hamed Akhlaghi 2018-08-08 16:11:34

Swift 4

Plage et Plage partielle subscripting en utilisant String'S indices propriété

Comme variation de @leodabus belle réponse , nous pouvons ajouter une extension supplémentaire à DefaultBidirectionalIndices dans le but de nous permettre de retomber sur la indices propriété de String lors de la mise en œuvre des indices personnalisés (par Int plages spécialisées et plages partielles) pour ce dernier.

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"

Merci @LeoDabus de m'avoir pointé dans la direction de l'utilisation du indices propriété comme une(autre) alternative à String subscripting!

Swift 4.2.

Dans Swift 4.2, DefaultBidirectionalIndices a été dépréciée en faveur de DefaultIndices.

2
répondu dfri 2018-09-01 02:19:51

Le type String de Swift ne fournit pas de méthode characterAtIndex car il existe plusieurs façons d'encoder une chaîne Unicode. Allez - vous avec UTF8, UTF16, ou autre chose?

Vous pouvez accéder aux collections CodeUnit en récupérant les propriétés String.utf8 et String.utf16. Vous pouvez également accéder à la collection UnicodeScalar en récupérant la propriété String.unicodeScalars.

Dans l'esprit de l'implémentation de NSString, je retourne un type unichar.

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
répondu Erik 2014-06-07 06:43:05

Une solution de type python, qui vous permet d'utiliser un index négatif,

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

Pourrait être:

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)]
        }
    }
}

En passant, il peut être utile de transposer toute la notation de tranche de Python

1
répondu Joseph Merdrignac 2017-05-23 12:18:28

Vous pouvez également convertir une chaîne en tableau de caractères comme ceci:

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

C'est le moyen d'obtenir char à l'index spécifié en temps constant.

L'exemple ci-dessous ne s'exécute pas en temps constant, mais nécessite un temps linéaire. Donc, si vous avez beaucoup de recherche dans String by index, utilisez la méthode ci-dessus.

let char = text[text.startIndex.advancedBy(index)]
1
répondu Marcin Kapusta 2016-03-10 15:29:01

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))
    }

}

L'Utilisation de

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

Utile de Programmation trucs et Astuces (écrit par moi)

1
répondu quemeful 2016-09-15 13:27:23

Utiliser caractères pour faire le travail. Vous pouvez rapidement convertir la chaîne en un tableau de caractères pouvant être manipulés par les méthodes CharacterView.

Exemple:

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

(full CharacterView doc)

(testé dans Swift 3)

1
répondu Stephane Paquet 2016-11-19 17:36:25

Il y a une alternative, expliquée dans String manifesto

extension String : BidirectionalCollection {
    subscript(i: Index) -> Character { return characters[i] }
}
1
répondu George Maisuradze 2017-09-25 13:46:39

Obtenir la première lettre:

first(str) // retrieve first letter

Plus ici: http://sketchytech.blogspot.com/2014/08/swift-pure-swift-method-for-returning.html

1
répondu philippinedev 2018-04-28 06:01:41

Get & Set Indice (String & Substring) - Swift 4.1

Swift 4.1, Xcode 9.3

J'ai basé ma réponse sur la réponse de @alecarlson. La seule grande différence est , vous pouvez obtenir un Substring ou String retourné (et, dans certains cas, un seul Character). Vous pouvez aussi get et set l'indice. Enfin, le mien est plus lourd et plus long que @alecarlson et en tant que tel, je vous suggère de le mettre dans un fichier source.


Extension:

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)")
        }
    }
}
1
répondu Noah Wilder 2018-05-08 13:27:23