Obtener el enésimo carácter de una cadena en Swift
¿Cómo puedo obtener el enésimo carácter de una cadena? Probé []
el descriptor de acceso bracket() sin suerte.
var string = "Hello, world!"
var firstChar = string[0] // Throws error
ERROR: 'subíndice' no está disponible: no se puede subíndice una cadena con un Int, consulte el comentario de la documentación para obtener más información
Atención: consulte la respuesta de Leo Dabus para conocer una implementación adecuada para Swift 4 y Swift 5.
Swift 4 o posterior
El Substring
tipo se introdujo en Swift 4 para hacer que las subcadenas sean más rápidas y eficientes al compartir almacenamiento con la cadena original, por lo que eso es lo que deberían devolver las funciones de subíndice.
Pruébalo aquí
extension StringProtocol {
subscript(offset: Int) -> Character { self[index(startIndex, offsetBy: offset)] }
subscript(range: Range<Int>) -> SubSequence {
let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
return self[startIndex..<index(startIndex, offsetBy: range.count)]
}
subscript(range: ClosedRange<Int>) -> SubSequence {
let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
return self[startIndex..<index(startIndex, offsetBy: range.count)]
}
subscript(range: PartialRangeFrom<Int>) -> SubSequence { self[index(startIndex, offsetBy: range.lowerBound)...] }
subscript(range: PartialRangeThrough<Int>) -> SubSequence { self[...index(startIndex, offsetBy: range.upperBound)] }
subscript(range: PartialRangeUpTo<Int>) -> SubSequence { self[..<index(startIndex, offsetBy: range.upperBound)] }
}
Para convertir Substring
en a String
, simplemente puede hacerlo String(string[0..2])
, pero solo debe hacerlo si planea mantener la subcadena. De lo contrario, es más eficiente mantenerlo como Substring
.
Sería fantástico si alguien pudiera encontrar una buena manera de fusionar estas dos extensiones en una. Intenté ampliar Nota: Esta respuesta ya ha sido editada, está implementada correctamente y ahora también funciona para subcadenas. Solo asegúrese de utilizar un rango válido para evitar fallas al subscribir su tipo StringProtocol. Para subíndices con un rango que no fallará con valores fuera de rango, puede usar esta implementaciónStringProtocol
sin éxito porque el index
método no existe allí.
¿Por qué no está integrado?
El mensaje de error dice "consulte el comentario de la documentación para su discusión" . Apple proporciona la siguiente explicación en el archivo UnavailableStringAPIs.swift :
La subscripción de cadenas con números enteros no está disponible.
El concepto de "el
i
carácter enésimo de una cadena" tiene diferentes interpretaciones en diferentes bibliotecas y componentes del sistema. Se debe seleccionar la interpretación correcta según el caso de uso y las API involucradas, por lo queString
no se puede subscribir 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. 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 Cocoa y Cocoa Touch procesan cadenas en términos de unidades de código UTF-16. Por ejemplo, instancias de desplazamientos y longitudes de subcadenasNSRange
utilizadasNSAttributedString
yNSRegularExpression
almacenadas en términos de unidades de código UTF-16.
String.unicodeScalars
es una colección de escalares Unicode. Utilice esta API cuando realice manipulación de bajo nivel de datos de personajes.
String.characters
es una colección de grupos 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 en la mayor medida posible el procesamiento carácter por carácter. Utilice en su lugar algoritmos Unicode sensibles a la configuración regional de alto nivel, por ejemplo,
String.localizedStandardCompare()
, etc.String.localizedLowercaseString
String.localizedStandardRangeOfString()
Rápido 5.2
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"
Deberá agregar esta extensión String a su proyecto (está completamente probada):
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])
}
}
Aunque Swift siempre tuvo una solución lista para usar para este problema (sin la extensión String, que proporcioné a continuación), recomiendo encarecidamente usar la extensión. ¿Por qué? Porque me ahorró decenas de horas de dolorosa migración desde las primeras versiones de Swift, donde la sintaxis de String cambiaba en casi cada versión, pero todo lo que necesitaba hacer era actualizar la implementación de la extensión en lugar de refactorizar todo el proyecto. Haz tu 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"
Se me acaba de ocurrir esta ingeniosa solución
var firstChar = Array(string)[0]