index swift string indexing

¿Cómo funciona String.Index en Swift?



substring swift 4 (3)

Cree un UITextView dentro de un tableViewController. Usé la función: textViewDidChange y luego verifiqué la entrada de la tecla de retorno. luego, si detectó la entrada de la tecla de retorno, elimine la entrada de la tecla de retorno y descarte el teclado.

func textViewDidChange(_ textView: UITextView) { tableView.beginUpdates() if textView.text.contains("/n"){ textView.text.remove(at: textView.text.index(before: textView.text.endIndex)) textView.resignFirstResponder() } tableView.endUpdates() }

He estado actualizando algunos de mis códigos y respuestas anteriores con Swift 3, pero cuando llegué a Swift Strings and Indexing fue muy difícil entender las cosas.

Específicamente estaba intentando lo siguiente:

let str = "Hello, playground" let prefixRange = str.startIndex..<str.startIndex.advancedBy(5) // error

donde la segunda línea me daba el siguiente error

''advancedBy'' no está disponible: para avanzar un índice en n pasos, llame a ''index (_: offsetBy :)'' en la instancia de CharacterView que produjo el índice.

Veo que String tiene los siguientes métodos.

str.index(after: String.Index) str.index(before: String.Index) str.index(String.Index, offsetBy: String.IndexDistance) str.index(String.Index, offsetBy: String.IndexDistance, limitedBy: String.Index)

Al principio me confundían mucho, así que comencé a jugar con ellos hasta que los entendí. Añado una respuesta a continuación para mostrar cómo se usan.



Todos los siguientes ejemplos usan

var str = "Hello, playground"

startIndex y endIndex

  • startIndex es el índice del primer carácter
  • endIndex es el índice después del último carácter.

Ejemplo

// character str[str.startIndex] // H str[str.endIndex] // error: after last character // range let range = str.startIndex..<str.endIndex str[range] // "Hello, playground"

Con los rangos unilaterales de Swift 4, el rango se puede simplificar a una de las siguientes formas.

let range = str.startIndex... let range = ..<str.endIndex

Usaré el formulario completo en los siguientes ejemplos por razones de claridad, pero por razones de legibilidad, probablemente querrá usar los rangos unilaterales en su código.

after

Como en: index(after: String.Index)

  • after refiere al índice del personaje directamente después del índice dado.

Ejemplos

// character let index = str.index(after: str.startIndex) str[index] // "e" // range let range = str.index(after: str.startIndex)..<str.endIndex str[range] // "ello, playground"

before

Como en: index(before: String.Index)

  • before refiere al índice del personaje directamente antes del índice dado.

Ejemplos

// character let index = str.index(before: str.endIndex) str[index] // d // range let range = str.startIndex..<str.index(before: str.endIndex) str[range] // Hello, playgroun

offsetBy

Como en: index(String.Index, offsetBy: String.IndexDistance)

  • El valor offsetBy puede ser positivo o negativo y comienza desde el índice dado. Aunque es del tipo String.IndexDistance , puede darle un Int .

Ejemplos

// character let index = str.index(str.startIndex, offsetBy: 7) str[index] // p // range let start = str.index(str.startIndex, offsetBy: 7) let end = str.index(str.endIndex, offsetBy: -6) let range = start..<end str[range] // play

limitedBy

Como en: index(String.Index, offsetBy: String.IndexDistance, limitedBy: String.Index)

  • limitedBy es útil para asegurarse de que el desplazamiento no haga que el índice se salga de los límites. Es un índice delimitador. Como es posible que el desplazamiento supere el límite, este método devuelve un Opcional. Devuelve nil si el índice está fuera de límites.

Ejemplo

// character if let index = str.index(str.startIndex, offsetBy: 7, limitedBy: str.endIndex) { str[index] // p }

Si el desplazamiento hubiera sido 77 lugar de 7 , entonces la declaración if se habría omitido.

¿Por qué se necesita String.Index?

Sería mucho más fácil usar un índice Int para cadenas. La razón por la que debe crear una nueva String.Index para cada Cadena es que los Personajes en Swift no tienen la misma longitud debajo del capó. Un solo personaje Swift puede estar compuesto por uno, dos o incluso más puntos de código Unicode. Por lo tanto, cada cadena única debe calcular los índices de sus caracteres.

Posiblemente es ocultar esta complejidad detrás de una extensión de índice Int, pero soy reacio a hacerlo. Es bueno recordar lo que realmente está sucediendo.