Recherche d’index de caractère dans Swift Ssortingng

Il est temps d’admettre la défaite …

En Objective-C, je pourrais utiliser quelque chose comme:

NSSsortingng* str = @"abcdefghi"; [str rangeOfSsortingng:@"c"].location; // 2 

Dans Swift, je vois quelque chose de similaire:

 var str = "abcdefghi" str.rangeOfSsortingng("c").startIndex 

… mais cela me donne juste un Ssortingng.Index , que je peux utiliser pour Ssortingng.Index dans la chaîne d’origine, mais sans extraire un emplacement.

FWIW, cette Ssortingng.Index a un ivar privé appelé _position qui contient la valeur correcte. Je ne vois pas comment il est exposé.

Je sais que je pourrais facilement append ceci à Ssortingng moi-même. Je suis plus curieux de savoir ce qui me manque dans cette nouvelle API.

Vous n’êtes pas le seul à ne pas trouver la solution.

Ssortingng RandomAccessIndexType pas RandomAccessIndexType . Probablement parce qu’ils permettent des caractères avec des longueurs d’octet différentes. C’est pourquoi nous devons utiliser ssortingng.characters.count ( count ou countElements dans Swift 1.x) pour obtenir le nombre de caractères. Cela s’applique également aux positions. Le _position est probablement un index dans le tableau brut d’octets et ils ne veulent pas exposer cela. Ssortingng.Index est destiné à nous protéger contre l’access aux octets au milieu des caractères.

Cela signifie que tout index que vous obtenez doit être créé à partir de Ssortingng.startIndex ou Ssortingng.endIndex ( Ssortingng.Index implémente BidirectionalIndexType ). Tout autre index peut être créé en utilisant les méthodes successor ou predecessor .

Maintenant, pour nous aider avec les index, il existe un ensemble de méthodes (fonctions dans Swift 1.x):

Swift 3.0

 let text = "abc" let index2 = text.index(text.startIndex, offsetBy: 2) //will call succ 2 times let lastChar: Character = text[index2] //now we can index! let characterIndex2 = text.characters.index(text.characters.startIndex, offsetBy: 2) let lastChar2 = text.characters[characterIndex2] //will do the same as above let range: Range = text.range(of: "b")! let index: Int = text.distance(from: text.startIndex, to: range.lowerBound) 

Swift 2.x

 let text = "abc" let index2 = text.startIndex.advancedBy(2) //will call succ 2 times let lastChar: Character = text[index2] //now we can index! let lastChar2 = text.characters[index2] //will do the same as above let range: Range = text.rangeOfSsortingng("b")! let index: Int = text.startIndex.distanceTo(range.startIndex) //will call successor/predecessor several times until the indices match 

Swift 1.x

 let text = "abc" let index2 = advance(text.startIndex, 2) //will call succ 2 times let lastChar: Character = text[index2] //now we can index! let range = text.rangeOfSsortingng("b") let index: Int = distance(text.startIndex, range.startIndex) //will call succ/pred several times 

Travailler avec Ssortingng.Index est fastidieux, mais l’utilisation d’un wrapper pour indexer par des entiers (voir https://stackoverflow.com/a/25152652/669586 ) est dangereux car cela cache l’inefficacité de l’indexation réelle.

Notez que l’implémentation de l’indexation Swift a pour problème que les index / plages créés pour une chaîne ne peuvent pas être utilisés de manière fiable pour une chaîne différente , par exemple:

Swift 2.x

 let text: Ssortingng = "abc" let text2: Ssortingng = "🎾🏇🏈" let range = text.rangeOfSsortingng("b")! //can randomly return a bad subssortingng or throw an exception let subssortingng: Ssortingng = text2[range] //the correct solution let intIndex: Int = text.startIndex.distanceTo(range.startIndex) let startIndex2 = text2.startIndex.advancedBy(intIndex) let range2 = startIndex2...startIndex2 let subssortingng: Ssortingng = text2[range2] 

Swift 1.x

 let text: Ssortingng = "abc" let text2: Ssortingng = "🎾🏇🏈" let range = text.rangeOfSsortingng("b") //can randomly return nil or a bad subssortingng let subssortingng: Ssortingng = text2[range] //the correct solution let intIndex: Int = distance(text.startIndex, range.startIndex) let startIndex2 = advance(text2.startIndex, intIndex) let range2 = startIndex2...startIndex2 let subssortingng: Ssortingng = text2[range2] 

Swift 3.0 rend cela un peu plus prolixe:

 let ssortingng = "Hello.World" let needle: Character = "." if let idx = ssortingng.characters.index(of: needle) { let pos = ssortingng.characters.distance(from: ssortingng.startIndex, to: idx) print("Found \(needle) at position \(pos)") } else { print("Not found") } 

Extension:

 extension Ssortingng { public func index(of char: Character) -> Int? { if let idx = characters.index(of: char) { return characters.distance(from: startIndex, to: idx) } return nil } } 

Dans Swift 2.0, cela est devenu plus facile:

 let ssortingng = "Hello.World" let needle: Character = "." if let idx = ssortingng.characters.indexOf(needle) { let pos = ssortingng.startIndex.distanceTo(idx) print("Found \(needle) at position \(pos)") } else { print("Not found") } 

Extension:

 extension Ssortingng { public func indexOfCharacter(char: Character) -> Int? { if let idx = self.characters.indexOf(char) { return self.startIndex.distanceTo(idx) } return nil } } 

Implémentation de Swift 1.x:

Pour une solution pure Swift, on peut utiliser:

 let ssortingng = "Hello.World" let needle: Character = "." if let idx = find(ssortingng, needle) { let pos = distance(ssortingng.startIndex, idx) println("Found \(needle) at position \(pos)") } else { println("Not found") } 

En tant qu’extension de Ssortingng :

 extension Ssortingng { public func indexOfCharacter(char: Character) -> Int? { if let idx = find(self, char) { return distance(self.startIndex, idx) } return nil } } 
 extension Ssortingng { // MARK: - sub Ssortingng func subssortingngToIndex(index:Int) -> Ssortingng { return self.subssortingngToIndex(advance(self.startIndex, index)) } func subssortingngFromIndex(index:Int) -> Ssortingng { return self.subssortingngFromIndex(advance(self.startIndex, index)) } func subssortingngWithRange(range:Range) -> Ssortingng { let start = advance(self.startIndex, range.startIndex) let end = advance(self.startIndex, range.endIndex) return self.subssortingngWithRange(start.. Character{ return self[advance(self.startIndex, index)] } subscript(range:Range) -> Ssortingng { let start = advance(self.startIndex, range.startIndex) let end = advance(self.startIndex, range.endIndex) return self[start.., withSsortingng: Ssortingng!) -> Ssortingng { var result:NSMutableSsortingng = NSMutableSsortingng(ssortingng: self) result.replaceCharactersInRange(NSRange(range), withSsortingng: withSsortingng) return result } } 

J’ai trouvé cette solution pour swift2:

 var str = "abcdefghi" let indexForCharacterInSsortingng = str.characters.indexOf("c") //returns 2 

Je ne suis pas sûr de savoir comment extraire la position de Ssortingng.Index, mais si vous êtes prêt à utiliser des frameworks Objective-C, vous pouvez passer à Object-C et le faire comme avant.

 "abcdefghi".bridgeToObjectiveC().rangeOfSsortingng("c").location 

Il semble que certaines méthodes NSSsortingng n’aient pas encore été (ou ne seront peut-être pas) scopes sur Ssortingng. On y pense aussi.

Voici une extension de chaîne propre qui répond à la question:

Swift 3:

 extension Ssortingng { var length:Int { return self.characters.count } func indexOf(target: Ssortingng) -> Int? { let range = (self as NSSsortingng).range(of: target) guard range.toRange() != nil else { return nil } return range.location } func lastIndexOf(target: Ssortingng) -> Int? { let range = (self as NSSsortingng).range(of: target, options: NSSsortingng.CompareOptions.backwards) guard range.toRange() != nil else { return nil } return self.length - range.location - 1 } func contains(s: Ssortingng) -> Bool { return (self.range(of: s) != nil) ? true : false } } 

Swift 2.2:

 extension Ssortingng { var length:Int { return self.characters.count } func indexOf(target: Ssortingng) -> Int? { let range = (self as NSSsortingng).rangeOfSsortingng(target) guard range.toRange() != nil else { return nil } return range.location } func lastIndexOf(target: Ssortingng) -> Int? { let range = (self as NSSsortingng).rangeOfSsortingng(target, options: NSSsortingngCompareOptions.BackwardsSearch) guard range.toRange() != nil else { return nil } return self.length - range.location - 1 } func contains(s: Ssortingng) -> Bool { return (self.rangeOfSsortingng(s) != nil) ? true : false } } 

Si vous souhaitez utiliser NSSsortingng, vous pouvez le déclarer explicitement:

 var someSsortingng: NSSsortingng = "abcdefghi" var someRange: NSRange = someSsortingng.rangeOfSsortingng("c") 

Je ne sais pas encore comment faire cela dans Swift.

Je sais que c’est vieux et une réponse a été acceptée, mais vous pouvez trouver l’index de la chaîne en quelques lignes de code en utilisant:

 var str : Ssortingng = "abcdefghi" let characterToFind: Character = "c" let characterIndex = find(str, characterToFind) //returns 2 

Quelques autres informations utiles sur les cordes Swift ici Les cordes Swift

Swift 4.0

 func indexInt(of char: Character) -> Int? { return index(of: char)?.encodedOffset } 

Cela a fonctionné pour moi,

 var loc = "abcdefghi".rangeOfSsortingng("c").location NSLog("%d", loc); 

cela a fonctionné aussi,

 var myRange: NSRange = "abcdefghi".rangeOfSsortingng("c") var loc = myRange.location NSLog("%d", loc); 

Si vous y réfléchissez, vous n’avez pas vraiment besoin de la version Int exacte de l’emplacement. Le Range ou même le Ssortingng.Index sont suffisants pour récupérer la sous-chaîne si nécessaire:

 let mySsortingng = "hello" let rangeOfE = mySsortingng.rangeOfSsortingng("e") if let rangeOfE = rangeOfE { mySsortingng.subssortingngWithRange(rangeOfE) // e mySsortingng[rangeOfE] // e // if you do want to create your own range // you can keep the index as a Ssortingng.Index type let index = rangeOfE.startIndex mySsortingng.subssortingngWithRange(Range(start: index, end: advance(index, 1))) // e // if you really really need the // Int version of the index: let numericIndex = distance(index, advance(index, 1)) // 1 (type Int) } 

Le plus simple est:

Dans Swift 3 :

  var textViewSsortingng:Ssortingng = "HelloWorld2016" guard let index = textViewSsortingng.characters.index(of: "W") else { return } let mentionPosition = textViewSsortingng.distance(from: index, to: textViewSsortingng.endIndex) print(mentionPosition) 

Si vous souhaitez connaître la position d’un caractère dans une chaîne en tant que valeur int , utilisez ceci:

 let loc = newSsortingng.range(of: ".").location 

Swift 4 Solution complète:

OffsetIndexableCollection (Ssortingng utilisant Int Index)

https://github.com/frogcjn/OffsetIndexableCollection-Ssortingng-Int-Indexable-

 let a = "01234" print(a[0]) // 0 print(a[0...4]) // 01234 print(a[...]) // 01234 print(a[..<2]) // 01 print(a[...2]) // 012 print(a[2...]) // 234 print(a[2...3]) // 23 print(a[2...2]) // 2 if let number = a.index(of: "1") { print(number) // 1 print(a[number...]) // 1234 } if let number = a.index(where: { $0 > "1" }) { print(number) // 2 } 

Ssortingng est un type de pont pour NSSsortingng, donc ajoutez

 import Cocoa 

à votre fichier rapide et utilisez toutes les “anciennes” méthodes.

Le type de variable Ssortingng in Swift contient différentes fonctions par rapport à NSSsortingng dans Objective-C. Et comme Sulthan l’a mentionné,

Swift Ssortingng n’implémente pas RandomAccessIndex

Ce que vous pouvez faire est de réduire votre variable de type Ssortingng en NSSsortingng (ceci est valable dans Swift). Cela vous donnera access aux fonctions de NSSsortingng.

 var str = "abcdefghi" as NSSsortingng str.rangeOfSsortingng("c").locationx // returns 2 

En termes de reflection, cela pourrait être appelé une inversion. Vous découvrez que le monde est rond plutôt que plat. “Vous n’avez pas vraiment besoin de connaître l’INDEX du personnage pour faire les choses avec lui.” Et en tant que programmeur C, j’ai trouvé cela difficile à prendre! Votre ligne “let index = letters.characters.indexOf (” c “)!” est suffisant par lui-même. Par exemple pour supprimer le c que vous pourriez utiliser …

  var letters = "abcdefg" //let index = letters.rangeOfSsortingng("c")!.startIndex //is the same as let index = letters.characters.indexOf("c")! range = letters.characters.indexOf("c")!...letters.characters.indexOf("c")! letters.removeRange(range) letters 

Cependant, si vous voulez un index dont vous avez besoin pour renvoyer un INDEX réel, vous ne devez pas avoir de valeur Int en tant que Int pour des opérations supplémentaires. Ces extensions renvoient un index, un décompte d’un caractère spécifique et une plage que démontrera ce code plug-in de terrain de jeu.

 extension Ssortingng { public func firstIndexOfCharacter(aCharacter: Character) -> Ssortingng.CharacterView.Index? { for index in self.characters.indices { if self[index] == aCharacter { return index } } return nil } public func returnCountOfThisCharacterInSsortingng(aCharacter: Character) -> Int? { var count = 0 for letters in self.characters{ if aCharacter == letters{ count++ } } return count } public func rangeToCharacterFromStart(aCharacter: Character) -> Range? { for index in self.characters.indices { if self[index] == aCharacter { let range = self.startIndex...index return range } } return nil } } var MyLittleSsortingng = "MyVery:important Ssortingng" var theIndex = MyLittleSsortingng.firstIndexOfCharacter(":") var countOfColons = MyLittleSsortingng.returnCountOfThisCharacterInSsortingng(":") var theCharacterAtIndex:Character = MyLittleSsortingng[theIndex!] var theRange = MyLittleSsortingng.rangeToCharacterFromStart(":") MyLittleSsortingng.removeRange(theRange!) 

Vous pouvez également trouver des index d’un caractère dans une seule chaîne comme celle-ci,

 extension Ssortingng { func indexes(of character: Ssortingng) -> [Int] { precondition(character.count == 1, "Must be single character") return self.enumerated().reduce([]) { partial, element in if Ssortingng(element.element) == character { return partial + [element.offset] } return partial } } } 

Ce qui donne le résultat dans [Ssortingng.Distance] ie. [Int], comme

 "apple".indexes(of: "p") // [1, 2] "element".indexes(of: "e") // [0, 2, 4] "swift".indexes(of: "j") // [] 

Si vous cherchez un moyen facile d’obtenir l’index de Caractère ou de Chaîne, consultez cette bibliothèque http://www.dollarswift.org/#indexof-char-character-int

Vous pouvez obtenir l’indexOf à partir d’une chaîne en utilisant une autre chaîne ou un modèle d’expression régulière

Pour obtenir l’index d’une sous-chaîne dans une chaîne avec Swift 2:

 let text = "abc" if let range = text.rangeOfSsortingng("b") { var index: Int = text.startIndex.distanceTo(range.startIndex) ... } 

En swift 2.0

 var ssortingngMe="Something In this.World" var needle="." if let idx = ssortingngMe.characters.indexOf(needle) { let pos=ssortingngMe.subssortingngFromIndex(idx) print("Found \(needle) at position \(pos)") } else { print("Not found") } 
 let myssortingng:Ssortingng = "indeep"; let findCharacter:Character = "d"; if (myssortingng.characters.contains(findCharacter)) { let position = myssortingng.characters.indexOf(findCharacter); NSLog("Position of c is \(myssortingng.startIndex.distanceTo(position!))") } else { NSLog("Position of c is not found"); } 

Je joue avec suivant

 extension Ssortingng { func allCharactes() -> [Character] { var result: [Character] = [] for c in self.characters { result.append(c) } return } } 

jusqu’à ce que je comprends le fourni maintenant c’est juste tableau de caractères

et avec

 let c = Array(str.characters) 

Si vous n’avez besoin que de l’index d’un caractère, la solution la plus simple et la plus rapide (comme l’a déjà souligné Pascal) est la suivante:

 let index = ssortingng.characters.index(of: ".") let intIndex = ssortingng.distance(from: ssortingng.startIndex, to: index) 

En ce qui concerne la transformation d’un Ssortingng.Index en Int , cette extension fonctionne pour moi:

 public extension Int { /// Creates an `Int` from a given index in a given ssortingng /// /// - Parameters: /// - index: The index to convert to an `Int` /// - ssortingng: The ssortingng from which `index` came init(_ index: Ssortingng.Index, in ssortingng: Ssortingng) { self.init(ssortingng.distance(from: ssortingng.startIndex, to: index)) } } 

Exemple d’utilisation correspondant à cette question:

 var testSsortingng = "abcdefg" Int(testSsortingng.range(of: "c")!.lowerBound, in: testSsortingng) // 2 testSsortingng = "🇨🇦🇺🇸🇩🇪👩‍👩‍👧‍👦\u{1112}\u{1161}\u{11AB}" Int(testSsortingng.range(of: "🇨🇦🇺🇸🇩🇪")!.lowerBound, in: testSsortingng) // 0 Int(testSsortingng.range(of: "👩‍👩‍👧‍👦")!.lowerBound, in: testSsortingng) // 1 Int(testSsortingng.range(of: "한")!.lowerBound, in: testSsortingng) // 5 

Important:

Comme vous pouvez le constater, il regroupe les grappes de graphèmes étendus et les caractères joints différemment de Ssortingng.Index . Bien sûr, c’est pourquoi nous avons Ssortingng.Index . N’oubliez pas que cette méthode considère les clusters comme des caractères singuliers, ce qui est plus proche de la précision. Si votre objective est de diviser une chaîne par un sharepoint code Unicode, ce n’est pas la solution pour vous.

Dans Swift 2.0 , la fonction suivante renvoie une sous-chaîne avant un caractère donné.

 func subssortingng(before sub: Ssortingng) -> Ssortingng { if let range = self.rangeOfSsortingng(sub), let index: Int = self.startIndex.distanceTo(range.startIndex) { return sub_range(0, index) } return "" } 

Swift 3

 extension Ssortingng { func subssortingng(from:Ssortingng) -> Ssortingng { let searchingSsortingng = from let rangeOfSearchingSsortingng = self.range(of: searchingSsortingng)! let indexOfSearchingSsortingng: Int = self.distance(from: self.startIndex, to: rangeOfSearchingSsortingng.upperBound ) let sortingmmedSsortingng = self.subssortingng(start: indexOfSearchingSsortingng , end: self.count) return sortingmmedSsortingng } } 
  // Using Swift 4, the code below works. // The problem is that Ssortingng.index is a struct. Use dot notation to grab the integer part of it that you want: ".encodedOffset" let strx = "0123456789ABCDEF" let si = strx.index(of: "A") let i = si?.encodedOffset // i will be an Int. You need "?" because it might be nil, no such character found. if i != nil { // You MUST deal with the optional, unwrap it only if not nil. print("i = ",i) print("i = ",i!) // "!" str1ps off "optional" specification (unwraps i). // or let ii = i! print("ii = ",ii) } // Good luck. 

extension Ssortingng {

 //Fucntion to get the index of a particular ssortingng func index(of target: Ssortingng) -> Int? { if let range = self.range(of: target) { return characters.distance(from: startIndex, to: range.lowerBound) } else { return nil } } //Fucntion to get the last index of occurence of a given ssortingng func lastIndex(of target: Ssortingng) -> Int? { if let range = self.range(of: target, options: .backwards) { return characters.distance(from: startIndex, to: range.lowerBound) } else { return nil } } 

}