tutorial programación programacion lenguaje español descargar curso swift string collections character

programación - swift tutorial español



Obtén el enésimo carácter de una cadena en el lenguaje de programación Swift (30)

¿Cómo puedo obtener el carácter n de una cadena? Probé el soporte ( [] ) de acceso sin suerte.

var string = "Hello, world!" var firstChar = string[0] // Throws error


Swift 4

Subíndices de rango y rango parcial usando String propiedad de indices String

Como variación de la respuesta agradable de @LeoDabus , podemos agregar una extensión adicional a DefaultBidirectionalIndices con el propósito de permitirnos recurrir a la propiedad de indices de String al implementar los subíndices personalizados (por rangos especializados Int y rangos parciales) para este último.

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"

Gracias a @LeoDabus por apuntarme en la dirección de usar la propiedad de indices como una (otra) alternativa a las suscripciones de String .

Swift 4.2.

En Swift 4.2, DefaultBidirectionalIndices ha quedado en desuso a favor de DefaultIndices .


Obtener y establecer subíndices (cadena y subcadena) - Swift 4.1

Swift 4.1, Xcode 9.3

mi respuesta en la respuesta de . La única gran diferencia es que puede obtener Substringo Stringdevolver (y en algunos casos, una sola Character). También puede gety setel subíndice. Por último, el mío es más engorroso y más largo que el de y, como tal, le sugiero que lo ponga en un archivo fuente.

Extensión:

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


Solución Swift 2.2:

La siguiente extensión funciona en Xcode 7, esta es una combinación de http://oleb.net/blog/2014/07/swift-strings/ solución y la conversión de sintaxis 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] } }


Swift 4

let str = "My String"

Cadena en el índice

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

Subcadena

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

Primeros n caracteres

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

Últimos n caracteres

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

Swift 2 y 3

str = "My String"

** Cadena en el índice **

Swift 2

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

Swift 3

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

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

Primeros n caracteres

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

Últimos n caracteres

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


Swift 4.2 y anteriores

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"

Necesitará agregar esta extensión de cadena a su proyecto (está completamente probado):

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

A pesar de que Swift siempre tuvo una solución inmediata para este problema (sin la extensión String, que proporcioné a continuación), todavía recomendaría encarecidamente usar la extensión. ¿Por qué? Porque me ahorró decenas de horas de migración dolorosa desde las primeras versiones de Swift, donde la sintaxis de String estaba cambiando en casi todas las versiones, pero todo lo que tenía que hacer era actualizar la implementación de la extensión en lugar de refactorizar toda la producción de líneas de código de 300k la aplicación Haga su elección.

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"


Acabo de llegar a esta solución ordenada

var firstChar = Array(string)[0]


Acabo de tener el mismo problema. Simplemente haga esto:

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


Actualización para 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)) } } }


Como nota aparte, hay algunas funciones aplicables directamente a la representación de cadena de caracteres de una cadena, como esta:

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

El resultado es de tipo Carácter, pero puedes convertirlo en una Cadena.

O esto:

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

:-)


Creo que una respuesta rápida para obtener el primer personaje podría ser:

let firstCharacter = aString[aString.startIndex]

Es mucho más elegante y rendimiento que:

let firstCharacter = Array(aString.characters).first

Pero ... si desea manipular y hacer más operaciones con cadenas, podría pensar crear una extensión ... hay una extensión con este enfoque, es muy similar a la que ya se ha publicado aquí:

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

}

¡PERO ES UNA IDEA TERRIBLE!

La extensión de abajo es horriblemente ineficiente. Cada vez que se accede a una cadena con un entero, se ejecuta una función O (n) para avanzar en su índice de inicio. La ejecución de un bucle lineal dentro de otro bucle lineal significa que este bucle es accidentalmente O (n2), a medida que aumenta la longitud de la cuerda, el tiempo que tarda este bucle aumenta cuadráticamente.

En lugar de hacer eso, puedes usar la colección de cadenas de los personajes.


El tipo String de Swift no proporciona un método characterAtIndex porque hay varias maneras de codificar una cadena Unicode. ¿Vas a ir con UTF8, UTF16 o algo más?

Puede acceder a las colecciones CodeUnit recuperando las propiedades String.utf8 y String.utf16 . También puede acceder a la colección UnicodeScalar recuperando la propiedad String.unicodeScalars .

En el espíritu de la NSString de NSString , estoy devolviendo un tipo 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]


La clase de cadena swift no proporciona la capacidad de obtener un carácter en un índice específico debido a su soporte nativo para los caracteres UTF. La longitud variable de un carácter UTF en la memoria hace que saltar directamente a un personaje sea imposible. Eso significa que tienes que recorrer manualmente la cadena cada vez.

Puede extender String para proporcionar un método que recorrerá los caracteres hasta que obtenga el índice deseado.

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


Mi solución está en una línea, suponiendo que la cadena es la cadena y 4 es la enésima posición que desea:

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

Simple ... Supongo que Swift incluirá más cosas sobre las subcadenas en versiones futuras.


Mi solución muy simple:

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


Para alimentar al sujeto y mostrar las posibilidades de subíndices Swift, aquí hay una pequeña cadena basada en subíndices "substring-toolbox"

Estos métodos son seguros y nunca pasan por encima de los índices de cadena.

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 ???


Si ve Cannot subscript a value of type ''String''... use esta extensión:

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

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


Sin indexación usando enteros, solo utilizando String.Index . Sobre todo con complejidad lineal. También puede crear rangos desde String.Index y obtener subcadenas usándolos.

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]

Tenga en cuenta que nunca podrá usar un índice (o rango) creado de una cadena a otra.

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]


Una solución similar a la de los pitones, que le permite usar un índice negativo,

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

podría ser:

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

Por cierto, puede valer la pena para transponer toda la notación de corte del pitón


Atención: consulte la respuesta de Leo Dabus para obtener una implementación adecuada para Swift 4.

Swift 4

El tipo de Substring se introdujo en Swift 4 para hacer que las subcadenas sean más rápidas y más eficientes al compartir el almacenamiento con la cadena original, de modo que eso es lo que deberían devolver las funciones de subíndice.

Pruébalo here

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

Para convertir la Substring en una String , simplemente puede hacer una String(string[0..2]) , pero solo debe hacerlo si planea mantener la cadena alrededor. De lo contrario, es más eficiente mantenerlo como una Substring .

Sería genial si alguien pudiera encontrar una buena manera de fusionar estas dos extensiones en una. Intenté extender StringProtocol sin éxito, porque el método de index no existe allí.

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

¿Por qué esto no está incorporado?

Apple proporciona la siguiente explicación (que se encuentra aquí ):

Las cadenas de subíndices con enteros no están disponibles.

El concepto de "el carácter i th en una cadena" tiene diferentes interpretaciones en diferentes bibliotecas y componentes del sistema. La interpretación correcta debe seleccionarse de acuerdo con el caso de uso y las API involucradas, por lo que String no puede ser subscripto con un entero.

Swift proporciona varias formas diferentes de acceder a los datos de caracteres almacenados dentro de las cadenas.

  • String.utf8 es una colección de unidades de código UTF-8 en la cadena. Utilice esta API al convertir la cadena a UTF-8. La mayoría de las API POSIX procesan cadenas en términos de unidades de código UTF-8.

  • String.utf16 es una colección de unidades de código UTF-16 en cadena. La mayoría de las API táctiles Cocoa y Cocoa procesan cadenas en términos de unidades de código UTF-16. Por ejemplo, las instancias de NSRange utilizadas con NSAttributedString y NSRegularExpression almacenan las compensaciones y longitudes de subcadenas en términos de unidades de código UTF-16.

  • String.unicodeScalars es una colección de escalares Unicode. Utilice esta API cuando esté realizando una manipulación de bajo nivel de datos de caracteres.

  • String.characters es una colección de agrupamientos de grafemas extendidos, que son una aproximación de los caracteres percibidos por el usuario.

Tenga en cuenta que al procesar cadenas que contienen texto legible, el procesamiento carácter por carácter debe evitarse en la mayor medida posible. En su lugar, use algoritmos Unicode sensibles al entorno local, por ejemplo, String.localizedStandardCompare() , String.localizedLowercaseString , String.localizedStandardRangeOfString() etc.


En Swift 3

let mystring = "Hello, world!" let stringToArray = Array(mystring.characters) let indices = (stringToArray.count)-1 print(stringToArray[0]) //H print(stringToArray[indices]) //!



Swift 2.0 a partir de Xcode 7 GM Seed

var text = "Hello, world!" let firstChar = text[text.startIndex.advancedBy(0)] // "H"

Para el enésimo carácter, reemplace 0 por n-1.

Edición: Swift 3.0

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


nb hay formas más simples de agarrar ciertos caracteres en la cadena

Por ejemplo, let firstChar = text.characters.first


Swift 3: otra solución (probada en el patio de recreo)

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

Uso:

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


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

Uso

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

Consejos y trucos útiles de programación (escritos por mí)


Swift 4.1 o posterior

Puede extender el StringProtocol de Swift 4 para que el subíndice esté disponible también para las subcadenas. Nota: Debido a la propuesta SE-0191 la extensión restringida a IndexDistance == Int se puede eliminar:

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

Pruebas

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 🇧🇷!!!"


Swift 4

String(Array(stringToIndex)[index])

Esta es probablemente la mejor manera de resolver este problema una sola vez. Probablemente desee convertir la cadena como una matriz primero, y luego lanzar el resultado como una cadena nuevamente. De lo contrario, se devolverá un carácter en lugar de una cadena.

String(Array("HelloThere")[1]) ejemplo String(Array("HelloThere")[1]) devolverá "e" como una cadena.

(Array("HelloThere")[1] devolverá "e" como un personaje.

Swift no permite que las cadenas se indexen como matrices, pero esto hace el trabajo, el estilo de fuerza bruta.


Swift3

Puede usar la sintaxis de los subíndices para acceder al Carácter en un índice de Cadena particular.

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

o podemos hacer una extensión de cadena en Swift 4

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

USO:

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


También puedes convertir String a Array of Characters así:

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

Esta es la forma de obtener char en un índice especificado en tiempo constante.

El siguiente ejemplo no se ejecuta en tiempo constante, pero requiere tiempo lineal. Entonces, si tiene muchas búsquedas en Cadena por índice, use el método anterior.

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


Hay una alternativa, explicada en el manifiesto de cuerdas.

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


Usar personajes haría el trabajo. Puede convertir rápidamente la Cadena en una matriz de caracteres que pueden ser manipulados por los métodos de CharacterView.

Ejemplo:

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

(completo CharacterView doc)

(probado en Swift 3)