He estado actualizando algunos de mis códigos y respuestas anteriores con Swift 3, pero cuando llegué a Swift Strings e Indexing con subcadenas, las cosas se volvieron confusas.
Específicamente estaba intentando lo siguiente:
let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)
donde la segunda línea me daba el siguiente error
El valor del tipo 'String' no tiene miembro 'substringWithRange'
Veo que String
tiene los siguientes métodos ahora:
str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)
Al principio me confundieron mucho, así que comencé a jugar con el índice y el rango . Esta es una pregunta y respuesta de seguimiento para la subcadena. Añado una respuesta a continuación para mostrar cómo se usan.
Respuestas:
Todos los siguientes ejemplos usan
Swift 4
Las cadenas obtuvieron una revisión bastante grande en Swift 4. Cuando obtienes una subcadena de una cadena ahora, obtienes un
Substring
tipo de regreso en lugar de unString
. ¿Por qué es esto? Las cadenas son tipos de valor en Swift. Eso significa que si usa una Cadena para hacer una nueva, entonces debe copiarse. Esto es bueno para la estabilidad (nadie más lo va a cambiar sin su conocimiento) pero malo para la eficiencia.Una subcadena, por otro lado, es una referencia a la cadena original de la que proviene. Aquí hay una imagen de la documentación que ilustra eso.
No se necesita copiar, por lo que es mucho más eficiente de usar. Sin embargo, imagina que tienes una subcadena de diez caracteres de una cadena de un millón de caracteres. Debido a que la Subcadena hace referencia a la Cadena, el sistema tendría que retener la Cadena completa mientras la Subcadena esté alrededor. Por lo tanto, cada vez que termine de manipular su Subcadena, conviértala en una Cadena.
Esto copiará solo la subcadena y la memoria que contiene la antigua cadena puede recuperarse . Las subcadenas (como tipo) están destinadas a ser de corta duración.
Otra gran mejora en Swift 4 es que las cadenas son colecciones (nuevamente). Eso significa que cualquier cosa que pueda hacer a una Colección, puede hacerlo a una Cadena (usar subíndices, iterar sobre los caracteres, filtrar, etc.).
Los siguientes ejemplos muestran cómo obtener una subcadena en Swift.
Obteniendo subcadenas
Usted puede obtener una subcadena de una cadena mediante el uso de subíndices o una serie de otros métodos (por ejemplo,
prefix
,suffix
,split
). Sin embargo, aún necesita usarString.Index
y no unInt
índice para el rango. (Ver mi otra respuesta si necesita ayuda con eso).Comienzo de una cuerda
Puede usar un subíndice (tenga en cuenta el rango unilateral Swift 4):
o
prefix
:o incluso más fácil:
Fin de una cuerda.
Usando subíndices:
o
suffix
:o incluso más fácil:
Tenga en cuenta que al usar el
suffix(from: index)
tuve que contar desde el final usando-10
. Eso no es necesario cuando solo se usasuffix(x)
, que solo toma los últimosx
caracteres de una Cadena.Rango en una cuerda
Nuevamente, simplemente usamos subíndices aquí.
Convertir
Substring
aString
No olvide que, cuando esté listo para guardar su subcadena, debe convertirla en a
String
para que se pueda limpiar la memoria de la cadena anterior.¿Usando una
Int
extensión de índice?Dudo en usar una
Int
extensión de índice basada después de leer el artículo Strings in Swift 3 de Airspeed Velocity y Ole Begemann. Aunque en Swift 4, las cadenas son colecciones, el equipo de Swift no ha utilizadoInt
índices a propósito . Está quietoString.Index
. Esto tiene que ver con que los caracteres Swift están compuestos por un número variable de puntos de código Unicode. El índice real tiene que calcularse de manera única para cada cadena.Tengo que decir que espero que el equipo de Swift encuentre una forma de abstraerse
String.Index
en el futuro. Pero hasta ellos elijo usar su API. Me ayuda a recordar que las manipulaciones de cadenas no son simplesInt
búsquedas de índice.fuente
garbage collected
;-) Espero que la gente aquí sepa que no hay recolección de basura en Swift.Estoy realmente frustrado con el modelo de acceso a cadenas de Swift: todo tiene que ser un
Index
. Todo lo que quiero es acceder al carácter i-ésimo de la cadena usandoInt
, no el índice torpe y avanzar (que cambia con cada lanzamiento importante). Entonces hice una extensión paraString
:fuente
let str = "🇨🇭🇩🇪🇺🇸Hello"
print(str.substring(to: 2))
str[5]
, quiero acceder al carácter en el índice 5, sea cual sea ese carácter o cuántos bytes se necesitan. ¿No se trata Swift de la productividad del desarrollador?countElement(str)
para encontrar la longitud. En Swift 3, Apple hizo que la cadena no se ajustaraSequence
y obligó a todos a usarlastr.characters
. Estos muchachos no tienen miedo de hacer cambios. Su terquedad en la suscripción de enteros es realmente difícil de entenderExtensión Swift 5:
Uso:
O unicode:
fuente
count
solo estaba disponible enself.characters
CountableClosedRange<Int>
si desea escribir, por ejemplos[0...2]
.Swift 4 y 5:
Cómo usarlo:
fuente
Swift 4
En rápido 4 se
String
ajusta aCollection
. En lugar desubstring
, ahora deberíamos usar unasubscript.
Así que si usted quiere cortar sólo la palabra"play"
de"Hello, playground"
, usted podría hacerlo de esta manera:Es interesante saber que hacerlo te dará un en
Substring
lugar de unString
. Esto es rápido y eficiente, ya queSubstring
comparte su almacenamiento con la cadena original. Sin embargo, compartir memoria de esta manera también puede conducir fácilmente a pérdidas de memoria.Es por eso que debe copiar el resultado en una nueva Cadena, una vez que desee limpiar la Cadena original. Puedes hacer esto usando el constructor normal:
Puede encontrar más información sobre la nueva
Substring
clase en la [documentación de Apple]. 1Entonces, si por ejemplo obtienes un
Range
como resultado de unNSRegularExpression
, puedes usar la siguiente extensión:fuente
text[Range( nsRange , in: text)!]
Aquí hay una función que devuelve la subcadena de una subcadena determinada cuando se proporcionan índices de inicio y fin. Para una referencia completa, puede visitar los enlaces que figuran a continuación.
Aquí hay un enlace a la publicación del blog que he creado para tratar la manipulación de cadenas de forma rápida. Manipulación de cadenas en swift (cubre swift 4 también)
O puedes ver esta esencia en github
fuente
Tuve la misma reacción inicial. Yo también estaba frustrado por cómo la sintaxis y los objetos cambian tan drásticamente en cada lanzamiento importante.
Sin embargo, me di cuenta por experiencia de que siempre sufro las consecuencias de tratar de luchar contra el "cambio", como tratar con personajes de varios bytes, lo cual es inevitable si estás mirando a una audiencia global.
Así que decidí reconocer y respetar los esfuerzos realizados por los ingenieros de Apple y hacer mi parte al comprender su mentalidad cuando se les ocurrió este enfoque "horrible".
En lugar de crear extensiones, que es solo una solución alternativa para hacerte la vida más fácil (no estoy diciendo que sean incorrectas o caras), ¿por qué no descubrir cómo están diseñadas ahora las cadenas para funcionar?
Por ejemplo, tenía este código que funcionaba en Swift 2.2:
y después de dejar de intentar que el mismo enfoque funcionara, por ejemplo, usando Substrings, finalmente entendí el concepto de tratar Strings como una colección bidireccional para la cual terminé con esta versión del mismo código:
Espero que esto contribuya ...
fuente
La misma frustración, esto no debería ser tan difícil ...
Compilé este ejemplo de cómo obtener posiciones para la (s) subcadena (s) de un texto más grande:
devuelve ("Why", 0, 3) ("subcadenas", 26, 36) ("Swift3", 40, 46)
fuente
Soy nuevo en Swift 3, pero mirando la
String
sintaxis (index) para analogía, creo que ese índice es como un "puntero" restringido a una cadena e Int puede ayudar como un objeto independiente. Usando la sintaxis de base + offset, entonces podemos obtener el i-ésimo carácter de la cadena con el siguiente código:Para un rango de caracteres (índices) de una cadena que usa la sintaxis de String (rango), podemos obtener de i-th a f-th caracteres con el siguiente código:
Para una subcadena (rango) de una cadena que usa String.substring (rango) podemos obtener la subcadena usando el siguiente código:
Notas:
La i-ésima y la f-ésima comienzan con 0.
Para f-th, uso offsetBY: f + 1, porque el rango de uso de suscripción .. <(operador medio abierto), no incluye la posición f-th.
Por supuesto, debe incluir errores de validación como índice no válido.
fuente
Swift 4+
Devuelve una subsecuencia de los primeros n caracteres, o la cadena completa si la cadena es más corta. (inspirado en: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/take.html )
Ejemplo:
fuente
Soy un pensamiento bastante mecánico. Aquí están los conceptos básicos ...
Swift 4 Swift 5
El resultado es una subcadena, lo que significa que es parte de la cadena original. Para obtener una cadena separada completa, solo use eg
Esto es lo que uso:
fuente
Swift 4
fuente
Creé una extensión simple para esto (Swift 3)
fuente
Aquí hay una implementación más genérica:
Esta técnica todavía se usa
index
para mantener los estándares de Swift e implica un personaje completo.Para subcadenas del tercer carácter:
He usado camello
subString
para indicar que devuelve ayString
no aSubstring
.fuente
Sobre la base de lo anterior, necesitaba dividir una cadena en un carácter que no se imprime y se deja caer el carácter que no se imprime. Desarrollé dos métodos:
que reuní usando algunas de las respuestas anteriores.
Debido a que una cadena es una colección, hice lo siguiente:
Lo que para mí fue más intuitivo. ¿Cuál es el mejor? No tengo forma de decir que ambos trabajan con Swift 5
fuente
Swift 4
"Subcadena" ( https://developer.apple.com/documentation/swift/substring ):
Ejemplo de cadena de extensión:
ejemplo de uso de la cadena de extensión:
fuente
Swift 5
let desiredIndex: Int = 7 let substring = str[String.Index(encodedOffset: desiredIndex)...]
Esta variable de subcadena le dará el resultado.
Simplemente aquí Int se convierte en Índice y luego puede dividir las cadenas. A menos que obtenga errores.
fuente