index first string swift

first - Encontrar el Γ­ndice del personaje en Swift String



swift string char at index (29)

Swift 3

extension String { func substring(from:String) -> String { let searchingString = from let rangeOfSearchingString = self.range(of: searchingString)! let indexOfSearchingString: Int = self.distance(from: self.startIndex, to: rangeOfSearchingString.upperBound ) let trimmedString = self.substring(start: indexOfSearchingString , end: self.count) return trimmedString } }

Es hora de admitir la derrota ...

En Objective-C, podría usar algo como:

NSString* str = @"abcdefghi"; [str rangeOfString:@"c"].location; // 2

En Swift, veo algo similar:

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

... pero eso solo me da un String.Index , que puedo utilizar para volver a String.Index en la cadena original, pero no para extraer una ubicación.

FWIW, ese String.Index tiene un ivar privado llamado _position que tiene el valor correcto en él. Simplemente no veo cómo está expuesto.

Sé que podría agregar esto fácilmente a String. Tengo más curiosidad sobre lo que me falta en esta nueva API.


Aquí hay una extensión de String limpia que responde a la pregunta:

Swift 3:

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

Swift 2.2:

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


Cadena de extensión {

//Fucntion to get the index of a particular string func index(of target: String) -> 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 string func lastIndex(of target: String) -> Int? { if let range = self.range(of: target, options: .backwards) { return characters.distance(from: startIndex, to: range.lowerBound) } else { return nil } }

}


En Swift 2.0 , la siguiente función devuelve una subcadena antes de un carácter determinado.

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


En swift 2.0

var stringMe="Something In this.World" var needle="." if let idx = stringMe.characters.indexOf(needle) { let pos=stringMe.substringFromIndex(idx) print("Found /(needle) at position /(pos)") } else { print("Not found") }


En términos de pensar esto podría llamarse una INVERSIÓN. Descubres que el mundo es redondo en lugar de plano. "Realmente no necesitas saber el ÍNDICE del personaje para hacer cosas con él". ¡Y como programador en C, me resulta difícil tomarlo también! Tu línea "let index = letters.characters.indexOf (" c ")!" es suficiente por sí mismo. Por ejemplo, para quitar la c, podrías usar ... (pegar en el patio de recreo)

var letters = "abcdefg" //let index = letters.rangeOfString("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

Sin embargo, si desea un índice, debe devolver un ÍNDICE real, no un valor Int, ya que un valor Int requeriría pasos adicionales para cualquier uso práctico. Estas extensiones devuelven un índice, un recuento de un personaje específico y un rango que demostrará este código de área de juegos para niños.

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


Encontré esta solución para swift2:

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


Esto funcionó para mí,

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

esto funcionó también,

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


La forma más simple es:

En Swift 3 :

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


No estoy seguro de cómo extraer la posición de String.Index, pero si está dispuesto a recurrir a algunos frameworks de Objective-C, puede pasar al objetivo-c y hacerlo de la misma manera que solía hacerlo.

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

Parece que algunos métodos NSString aún no han sido (o quizás no serán) portados a String. Contiene también viene a la mente.


Para obtener el índice de una subcadena en una cadena con Swift 2:

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


Sé que esto es antiguo y se ha aceptado una respuesta, pero puedes encontrar el índice de la cadena en un par de líneas de código usando:

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

Alguna otra gran información sobre Swift strings aquí Strings in Swift


Si desea conocer la posición de un carácter en una cadena como un valor int , use esto:

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


Si desea utilizar NSString familiar, puede declararlo explícitamente:

var someString: NSString = "abcdefghi" var someRange: NSRange = someString.rangeOfString("c")

Todavía no estoy seguro de cómo hacer esto en Swift.



Si lo piensas, realmente no necesitas la versión Int exacta de la ubicación. El rango o incluso el índice de cadena es suficiente para sacar la subcadena de nuevo si es necesario:

let myString = "hello" let rangeOfE = myString.rangeOfString("e") if let rangeOfE = rangeOfE { myString.substringWithRange(rangeOfE) // e myString[rangeOfE] // e // if you do want to create your own range // you can keep the index as a String.Index type let index = rangeOfE.startIndex myString.substringWithRange(Range<String.Index>(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) }


Si solo necesita el índice de un personaje, la solución más simple y rápida (como ya lo señaló Pascal) es:

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


Sobre el tema de convertir un String.Index en un Int , esta extensión funciona para mí:

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

Ejemplo de uso relevante para esta pregunta:

var testString = "abcdefg" Int(testString.range(of: "c")!.lowerBound, in: testString) // 2 testString = "πŸ‡¨πŸ‡¦πŸ‡ΊπŸ‡ΈπŸ‡©πŸ‡ͺπŸ‘©‍πŸ‘©‍πŸ‘§‍πŸ‘¦/u{1112}/u{1161}/u{11AB}" Int(testString.range(of: "πŸ‡¨πŸ‡¦πŸ‡ΊπŸ‡ΈπŸ‡©πŸ‡ͺ")!.lowerBound, in: testString) // 0 Int(testString.range(of: "πŸ‘©‍πŸ‘©‍πŸ‘§‍πŸ‘¦")!.lowerBound, in: testString) // 1 Int(testString.range(of: "ᄒᅑᆫ")!.lowerBound, in: testString) // 5

Importante:

Como puede ver, agrupa los clústeres de grafemas extendidos y los caracteres unidos de forma diferente a String.Index . Por supuesto, esta es la razón por la cual tenemos String.Index . Debe tener en cuenta que este método considera que los clústeres son caracteres singulares, lo que está más cerca de ser correcto. Si su objetivo es dividir una cadena por punto de código Unicode, esta no es la solución para usted.


String es un tipo de puente para NSString, así que agregue

import Cocoa

a su archivo rápido y use todos los métodos "antiguos".


Swift 4 Solución completa:

OffsetIndexableCollection (String using Int Index)

https://github.com/frogcjn/OffsetIndexableCollection-String-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 }


También puedes encontrar índices de un personaje en una sola cadena como esta,

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

Lo que da el resultado en [String.Distance] es decir. [Int], como

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


Usted no es el único que no pudo encontrar la solución.

String no implementa RandomAccessIndexType . Probablemente porque habilitan caracteres con diferentes longitudes de bytes. Es por eso que tenemos que usar string.characters.count ( count o countElements en Swift 1.x) para obtener el número de caracteres. Eso también se aplica a las posiciones. La _position es probablemente un índice en la matriz sin formato de bytes y no quieren exponer eso. El String.Index está destinado a protegernos del acceso a los bytes en el medio de los caracteres.

Eso significa que cualquier índice que obtenga debe crearse desde String.startIndex o String.endIndex ( String.Index implementa BidirectionalIndexType ). Cualquier otro índice puede crearse utilizando métodos successor o predecessor .

Ahora, para ayudarnos con los índices, existe un conjunto de métodos (funciones en 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<String.Index> = 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<String.Index> = text.rangeOfString("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.rangeOfString("b") let index: Int = distance(text.startIndex, range.startIndex) //will call succ/pred several times

Trabajar con String.Index es engorroso, pero usar un contenedor para indexar por enteros (consulte https://.com/a/25152652/669586 ) es peligroso porque oculta la ineficacia de la indexación real.

Tenga en cuenta que la implementación de indexación de Swift tiene el problema de que los índices / rangos creados para una cadena no se pueden usar de manera confiable para una cadena diferente , por ejemplo:

Swift 2.x

let text: String = "abc" let text2: String = "πŸŽΎπŸ‡πŸˆ" let range = text.rangeOfString("b")! //can randomly return a bad substring or throw an exception let substring: String = text2[range] //the correct solution let intIndex: Int = text.startIndex.distanceTo(range.startIndex) let startIndex2 = text2.startIndex.advancedBy(intIndex) let range2 = startIndex2...startIndex2 let substring: String = text2[range2]

Swift 1.x

let text: String = "abc" let text2: String = "πŸŽΎπŸ‡πŸˆ" let range = text.rangeOfString("b") //can randomly return nil or a bad substring let substring: String = text2[range] //the correct solution let intIndex: Int = distance(text.startIndex, range.startIndex) let startIndex2 = advance(text2.startIndex, intIndex) let range2 = startIndex2...startIndex2 let substring: String = text2[range2]


Variable type String en Swift contiene diferentes funciones en comparación con NSString en Objective-C. Y como Sulthan mencionó,

Swift String no implementa RandomAccessIndex

Lo que puede hacer es disminuir su variable de tipo Cadena a NSString (esto es válido en Swift). Esto le dará acceso a las funciones en NSString.

var str = "abcdefghi" as NSString str.rangeOfString("c").locationx // returns 2


Yo juego con los siguientes

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

hasta que entienda el proporcionado ahora es solo una matriz de caracteres

y con

let c = Array(str.characters)


Swift 3.0 lo hace un poco más detallado:

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

Extensión:

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

En Swift 2.0 esto se ha vuelto más fácil:

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

Extensión:

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

Implementación de Swift 1.x:

Para una solución Swift pura, se puede usar:

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

Como una extensión de String :

extension String { public func indexOfCharacter(char: Character) -> Int? { if let idx = find(self, char) { return distance(self.startIndex, idx) } return nil } }


Swift 4.0

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


// Using Swift 4, the code below works. // The problem is that String.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 String { // MARK: - sub String func substringToIndex(index:Int) -> String { return self.substringToIndex(advance(self.startIndex, index)) } func substringFromIndex(index:Int) -> String { return self.substringFromIndex(advance(self.startIndex, index)) } func substringWithRange(range:Range<Int>) -> String { let start = advance(self.startIndex, range.startIndex) let end = advance(self.startIndex, range.endIndex) return self.substringWithRange(start..<end) } subscript(index:Int) -> Character{ return self[advance(self.startIndex, index)] } subscript(range:Range<Int>) -> String { let start = advance(self.startIndex, range.startIndex) let end = advance(self.startIndex, range.endIndex) return self[start..<end] } // MARK: - replace func replaceCharactersInRange(range:Range<Int>, withString: String!) -> String { var result:NSMutableString = NSMutableString(string: self) result.replaceCharactersInRange(NSRange(range), withString: withString) return result } }


let mystring:String = "indeep"; let findCharacter:Character = "d"; if (mystring.characters.contains(findCharacter)) { let position = mystring.characters.indexOf(findCharacter); NSLog("Position of c is /(mystring.startIndex.distanceTo(position!))") } else { NSLog("Position of c is not found"); }