Obtener el n-ésimo carácter de una cadena en el lenguaje de progtwigción Swift

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

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

Atención: Consulte la respuesta de Leo Dabus para 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 eficientes al compartir el almacenamiento con la cadena original, por lo que las funciones del subíndice deberían regresar.

Pruébelo aquí

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

Para convertir la Substring en una String , simplemente puede hacer String(string[0..2]) , pero solo debe hacer eso si planea mantener la subcadena 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 sola. 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) -> 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í ):

La subscripción de cadenas con enteros no está disponible.

El concepto de "el carácter i ésimo 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 se puede suscribir con un número entero.

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

  • String.utf8 es una colección de unidades de código UTF-8 en la cadena. Use 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 touch de Cocoa y Cocoa procesan cadenas en términos de unidades de código UTF-16. Por ejemplo, instancias de NSRange usadas con NSAttributedString y NSRegularExpression NSAttributedString NSRegularExpression almacenamiento y longitudes en términos de unidades de código UTF-16.

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

  • String.characters es una colección de clústeres 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 por humanos, se debe evitar el procesamiento carácter por carácter en la mayor medida posible. Utilice en su lugar algoritmos Unicode sensibles a la configuración regional de alto nivel, por ejemplo, String.localizedStandardCompare() , String.localizedLowercaseString , String.localizedStandardRangeOfString() etc.

String admite subíndices (acceso con [] ) fuera de la caja:

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" 

Usando sus propias extensiones, puede usar una syntax más concisa:

 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" 

... su extensión de cadena debería ser como (completamente probada):

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

Sin indexación con enteros, solo con String.Index . En su mayoría 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.. 

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

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

 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] 

Me acabo de ocurrir esta solución ordenada

 var firstChar = Array(string)[0] 

Xcode 9.3 • Swift 4.1 o posterior

Puede extender 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 puede eliminarse:

 extension StringProtocol { func index(at offset: Int, from start: Index? = nil) -> Index? { return index(start ?? startIndex, offsetBy: offset, limitedBy: endIndex) } func character(at offset: Int) -> Character? { precondition(offset >= 0, "offset can't be negative") guard let index = index(at: offset) else { return nil } return self[index] } subscript(_ range: CountableRange) -> SubSequence { precondition(range.lowerBound >= 0, "lowerBound can't be negative") let start = index(at: range.lowerBound) ?? endIndex let end = index(at: range.count, from: start) ?? endIndex return self[start..) -> SubSequence { precondition(range.lowerBound >= 0, "lowerBound can't be negative") let start = index(at: range.lowerBound) ?? endIndex let end = index(at: range.count, from: start) ?? endIndex return self[start..) -> SubSequence { return prefix(range.upperBound) } subscript(_ range: PartialRangeThrough) -> SubSequence { return prefix(range.upperBound + 1) } subscript(_ range: PartialRangeFrom) -> SubSequence { return suffix(Swift.max(0, count - range.lowerBound)) } } extension Substring { var string: String { return String(self) } } 

Swift 4’s solo necesita restringir IndexDistance igual a Int y devolver una SubSequence lugar de una Substring :

Xcode 9 • Swift 4

 extension StringProtocol where IndexDistance == Int { // same code } 

Para la versión de Swift 3 , revise el historial de edición


Pruebas

 let test = "Hello USA 🇺🇸!!! Hello Brazil 🇧🇷!!!" test.character(at: 10) // "🇺🇸" test.character(at: 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[..<10][...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

 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" 

Primero n caracteres

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

Último n caracteres

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

Swift 2 y 3

 str = "My String" 

** Cadena en í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)] 

Primero n caracteres

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

Último n caracteres

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

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 con n-1.

Editar: Swift 3.0

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

nb hay formas más simples de agarrar ciertos personajes en la cuerda

por ejemplo, let firstChar = text.characters.first

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) -> String { let start = index(startIndex, offsetBy: r.lowerBound) let end = index(startIndex, offsetBy: r.upperBound) return self[start..) -> 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) -> String { let start = advance(startIndex, integerRange.startIndex) let end = advance(startIndex, integerRange.endIndex) let range = start.. 

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

Solución Swift 2.2:

La siguiente extensión funciona en Xcode 7, esta es una combinación de esta solución y la conversión de syntax Swift 2.0.

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

La clase de cadena rápida no proporciona la capacidad de obtener un personaje en un índice específico debido a su compatibilidad nativa con 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 tiene que pasar manualmente la cadena cada vez.

Puede extender String para proporcionar un método que recorra los caracteres hasta su í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)! 

Como nota adicional, hay algunas funciones que se pueden aplicar 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 a una Cadena.

O esto:

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

🙂

Swift 4

 String(Array(stringToIndex)[index]) 

Esta es probablemente la mejor forma de resolver este problema por única vez. Es probable que desee convertir el String en una matriz primero, y luego lanzar el resultado como una cadena de nuevo. De lo contrario, se devolverá un carácter en lugar de una cadena.

Ejemplo de String(Array("HelloThere")[1]) devolverá “e” como una cadena.

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

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

Solo tuve el mismo problema. Simplemente haz esto:

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

Mi solución está en una línea, suponiendo que 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 subcadenas en futuras versiones.

Mi solución muy simple:

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

Con el fin de alimentar el tema y mostrar posibilidades de subíndices rápidos, aquí hay un pequeño subíndice de cadenas “substring-toolbox” basado

Estos métodos son seguros y nunca pasan por los índices de cadenas

 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) -> 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, 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 = 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 ??? 

Actualización para swift 2.0 subString

 public extension String { public subscript (i: Int) -> String { return self.substringWithRange(self.startIndex..) -> String { get { return self.substringWithRange(self.startIndex.advancedBy(r.startIndex).. 

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 quieres manipular y hacer más operaciones con cadenas, podrías pensar en crear una extensión. Hay una extensión con este enfoque, es bastante similar a la que ya hemos 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) -> String { let start = startIndex.advancedBy(integerRange.startIndex) let end = startIndex.advancedBy(integerRange.endIndex) let range = start.. 

}

¡PERO ES UNA IDEA TERRIBLE!

La extensión a continuación es horriblemente ineficiente. Cada vez que se accede a una cadena con un entero, se ejecuta una función O (n) para avanzar su índice inicial. Ejecutar 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 toma este bucle aumenta de forma cuadrática.

En lugar de hacer eso, podrías usar la colección de cuerdas de los personajes.

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 3: otra solución (probado 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 

Swift3

Puede usar la syntax del subíndice para acceder al carácter en un índice de cadena en 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 

Swift 4

Subcontratación de rango y rango parcial utilizando 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 intervalos especializados 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) -> SubSequence { return self[indices[r.lowerBound]...indices[r.upperBound]] } subscript(r: CountablePartialRangeFrom) -> SubSequence { return self[indices[r.lowerBound]...] } subscript(r: PartialRangeThrough) -> SubSequence { return self[...indices[r.upperBound]] } subscript(r: PartialRangeUpTo) -> SubSequence { return self[.. 

¡Gracias @LeoDabus por apuntarme en el sentido de usar la propiedad de indices como una (otra) alternativa a String subscripción String !

Swift 4.2.

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

El tipo String de Swift no proporciona un método characterAtIndex porque hay varias formas en que se podría codificar una cadena Unicode. ¿Vas 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] 

Una solución tipo python, 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 transponer la notación de división de la python completa

También puede convertir String en una matriz de caracteres como esa:

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

Esta es la manera de obtener char en el índice especificado en tiempo constante.

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

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

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) -> String { return substring(with: self.characters.index(self.startIndex, offsetBy: r.lowerBound)..) -> String { return substring(with: self.characters.index(self.startIndex, offsetBy: r.lowerBound).. 

Uso

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

Helpful Programming Tips and Tricks (written by me)

Using characters would do the job. You can quickly convert the String to an array of characters that can be manipulated by the CharacterView methods.

Ejemplo:

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

(full CharacterView doc)

(tested in Swift 3)

There’s an alternative, explained in String manifesto

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

Get the first letter:

 first(str) // retrieve first letter 

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

Get & Set Subscript (String & Substring) – Swift 4.1

Swift 4.1, Xcode 9.3

I based my answer off of @alecarlson ‘s answer. The only big difference is you can get a Substring or a String returned (and in some cases, a single Character ). You can also get and set the subscript. Lastly, mine is a more cumbersome and longer than @alecarlson ‘s and as such, I suggest you put it in a source file.


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