Swift – String

Sobre el tipo de dato String ya hablamos con enterioridad a modo de introducción. En esta ocación quiero ir un poco más allá, y abordar esos matices que nos harán conocer y aprovechar mucho más lo que este tipo de dato puede ofrecer.

Ni de lejos este artículo es una guía completa de todas las funcionalidades que ofrece la estructura String, lo que sí te aseguro es que abordaremos las más importantes, las de uso más frecuente. Como siempre a través de ejemplos y sus explicaciones.

¿Qué es una cadena de texto?

Una cadena es una secuencia de caracteres, digase «Hola» o textos mucho más extensos. Swift nos permite trabajar con cadenas de texto mediante la estructura String, la cual no solo es compatible con Unicode y nos permite almacenar datos de este tipo, sino que también nos provee de todo un set de acciones que podemos ejecutar sobre la cadena almacenada.

A estas acciones me refería cuando dije que habían matices que no vimos en el artículo sobre tipos de datos. Pero antes terminemos con los básico, ¿Cómo declaramos una variable de tipo String?

var name: String = ""
var emptyString = ""
var anotherEmptyString = String()

let greeting = "Hola"

let ohmSign = "\u{03A9}"

let multiline = """

 Cuando declaramos una variable o constante String de esta manera,
 podemos segmentar el texto en varias líneas.

 Dejar espacios entre ellas y aplicar:       tabulaciones!

 En ocaciones puede reultar muy conveniente.
 
"""

Expliquemos una a una cada una de estas declaraciones:

  • En la primera línea declaramos explicitamente que la variable es de tipo String y la inicializamos con el valor «», es decir con una cadena de texto vacia.
  • Luego declaramos otra variable, en esta ocación no especificamos el tipo de dato ya que el compilador lo infiere a través del valor que le hemos asignado «».
  • El tercer ejemplo es similar al primero, nos valemos del tipo de dato String y en este caso de su constructor para asignar un texto vacio a la variable.
  • A partir del cuarto ejemplo ya definimos constantes con contenido asociado. En este caso es un saludo, una cadena de texto simple, un «Hola».
  • El nombre de la constante del quinto ejemplo lo dice todo. Aquí hemos declarado una constante de tipo String con la representación Unicode del signo de ohm Ω.
  • En el último ejemplo mostramos como declarar una variable de tipo String inicializándola con las tres comillas. Esto nos permite más felixibilidad a la hora de formatear el texto. Podemos dejar líneas en blanco, aplicar tabulaciones, saltos de línea, todo de una manera bien sencilla y visual.

Caracteres

Hay otra manera de crear un String, y es mediante un arreglo de tipo Character. En una variable o constante de tipo Character podemos almacenar eso mismo, un caracter:

let questionMark: Character = "?"

let aLetter: Character = "a"

En este caso tenemos que especificar el tipo ya que de lo contrario Swift lo infiere como de tipo String.

También podemos iterar por los caracteres de una cadena de texto, ¿cómo si fuese un arreglo? exacto, como un arreglo de elementos de tipo Character.

for character in "Cat 🐱" {
    
    print(character)
    
} // for

De aquí viene la otra manera de crear un String, veamos:

let dogCharacters: [Character] = ["D", "o", "g", " ", "🐶"]

let dogString = String(dogCharacters)

print(dogString)

La salida en pantalla sería:

Dog 🐶

Es decir que mediante un arreglo de tipo Character podemos que crear un String, pasando el arreglo como parámetro al constructor de la estructura String.

¿Qué es un literal String?

Un literal String es básicamente un texto plano dentro de un par de comillas («Esto es un literal String.»). Una declaración explícita de una cadena de texto, una secuencia fija de caracteres.

Podemos utilizar una cadena literal como un valor inicial para una variable o constante, tal y como hemos visto en ejemplos anteriores:

let someString = "Esta cadena de texto es un valor literal."

En relación a este ejemplo y como ya he explicado Swift infiere el tipo String para la constante someString, ya que esta se inicializa con un valor literal de cadena de texto.

Interpolación

La interpolación en una cadena de caracteres es una manera de construir un nuevo objeto String a partir de una mezcla de constantes, variables, literales y expresiones mediante la inclusión de sus valores dentro de una cadena literal. Cada elemento que se inserta en la cadena literal se envuelve en un par de paréntesis, precedido por una barra invertida:

let multiplicador = 3

let mensaje = "\(multiplicador) veces 2.5 es \(Double(multiplicador) * 2.5)"

la salida en pantalla:

3 veces 2.5 es 7.5

En el ejemplo anterior, el valor de la variable multiplicador se inserta en una cadena literal como (multiplicador). Como podemos inferir de la salida en pantalla, este marcador de posición se sustituye con el valor real de la variable (multiplicador) cuando se evalúa la interpolación de cadenas como parte del proceso de crear la cadena en su versión final.

El valor de la variable multiplicador es también parte de otra expresión de la misma cadena literal, esta expresión calcula el valor de (Double(multiplicador) * 2.5) y como acabamos de explicar se inserta el resultado (7.5) en sustitución de la expresión.

¿Está vacía la variable?

Comprobar que nuestra variable está vacía es algo bien trivial, basta con acceder a la propiedad booleana isEmpty:

if emptyString.isEmpty {

     print ("Nada que ver aquí")

} // if

¿Cuántas palabras y caractéres tiene?

Conocer la cantidad de caracteres que tiene una variable String es bien sencillo en Swift:

let texto = "Esta es una oración de ejemplo."

print("El texto tiene: \(texto.count) caracteres.")

En el caso de las palabras lo podemos lograr de esta manera:

let texto = "Esta es una oración de ejemplo, como tantas otras."

let chararacterSet = CharacterSet.whitespacesAndNewlines.union(.punctuationCharacters)

let components = texto.components(separatedBy: chararacterSet)

let words = components.filter { word in
    
    !word.isEmpty

} // filter

print("El texto tiene: \(words.count) palabras.")

Aquí nos hemos valido de CharacterSet para especificar los caracteres que se considerarán separaciones entre las palabras. Dígase los espacios en blancos, los saltos de línea y los caracteres como las comas, el punto, el punto y coma, etc.

Luego mediante el método components pasamos lo que deseamos que sea considerado como separadores, y este nos devuelve un arreglo con los bloques en los que ha separado nuestra oración. Si luego de:

let components = texto.components(separatedBy: chararacterSet)

agregamos la línea:

print("Bloques: \(components)")

podremos visualizar lo siguiente en pantalla:

Bloques: ["Esta", "es", "una", "oración", "de", "ejemplo", "", "como", "tantas", "otras", ""]

Como podemos observar la coma y el punto se sustituyen por un caracter vacío «». Por esto es que luego tenemos que filtrarlos de nuestro arreglo para solo quedarnos con las palabras reales, y esto es lo que hacemos en el bloque siguiente a través de la función de órden superior filter.

Nota: Este ejemplo es un poco más complejo, y una explicación detallada está fuera del alcance de este artículo. El tema closures, programación funcional, dígase funciones de grado superior, todo esto se verá más adelante en otros artículos.

Concatenar cadenas de texto

Otra funcionalidad bastante útil y de uso frecuente es la concatenación de cadenas. Hay varias maneras de lograr esto

let poem = "En las noches claras, resuelvo el problema de la soledad del ser. Invito al sol y con mi sombra somos tres."

let poemName = "En las noches claras"
let poemAuthor = "Gloria Fuentes"

let poemFormatted = poem + poemAuthor

print(poemFormatted)

Una de las maneras más clásicas, y digo clásicas porque es algo común en otros lenguajes, es utilizar el operador de suma (+). Mediante él, y haciendo referencia al ejemplo, concatenamos la cadena de la izquierda con la de la derecha, y el resultado se almacena en poemFormatted. El valor de poem y poemAuthor no se ha modificado, solo se ha hecho referencia a estos en plan solo lectura, como si estuviaramos imprimiendo los valores.

La salida en pantalla sería:

En las noches claras, resuelvo el problema de la soledad del ser. Invito al sol y con mi sombra somos tres.Gloria Fuentes

Como podemos observar entre el punto final del poema y el nombre de la autora no hay espacio, para corregir esto pudiéramos modificar ligeramente el ejemplo y agregar el espacio:

let poemFormatted = poem + " " + poemAuthor

Pero una vez que nos ponemos creativos esta sintaxis se vuelve un poco engorrosa. Si por ejemplo queremos dar un poco más de formato; agregar el nombre del autor en la línea siguiente y poner el nombre del poema entre parentesis:

let poemFormatted = poem + "\n\n" + poemAuthor + " (" + poemName + ")"

Algo así sería bien horrible, en casos como este donde queremos concatenar varias cadenas de texto, la interpolación de cadenas sería un mejor enfoque, algo así:

let poemFormatted = String("\(poem) \n\n\(poemAuthor) (\(poemName))")

o bien utilizando la interpolación de cadenas en conjunción con las tres comillas:

let poemFormatted = """

 \(poem)

 \(poemAuthor) (\(poemName))

"""

La salida en pantalla:


 En las noches claras, resuelvo el problema de la soledad del ser. Invito al sol y con mi sombra somos tres.

 Gloria Fuentes (En las noches claras)

Remplazar un String con otro

Resulta que hemos cometido un error en la transcripción del poema, en lugar de «al sol» es «a la luna», y es que en la noches claras por my claras que sean no sale el sol.

En caso de que no podamos editar directamente la cadena de texto, siempre podemos hacer uso del método, replacingOccurrences que funciona de esta manera:

let readyForPublishing = poemFormatted.replacingOccurrences(of: "al sol", with: "a la luna")

en el primer parámetro pasamos el segmento de texto que deseamos remplazar y en el último el texto que remplazará al primero.

La versión final de nuestro ejemplo sería:

let poem = "En las noches claras, resuelvo el problema de la soledad del ser. Invito al sol y con mi sombra somos tres."

let poemName = "En las noches claras"
let poemAuthor = "Gloria Fuentes"

let poemFormatted = """

 \(poem)

 \(poemAuthor) (\(poemName))

"""

let readyForPublishing = poemFormatted.replacingOccurrences(of: "al sol", with: "a la luna")

print(readyForPublishing)

La salida en pantalla:


 En las noches claras, resuelvo el problema de la soledad del ser. Invito a la luna y con mi sombra somos tres.

 Gloria Fuentes (En las noches claras)

Buscar dentro de un String

Un objeto String nos permite buscar dentro del contenido que almacena, para esto nos valemos de tres funciones:

  • contains: A este método le pasamos como parametro una cadena de caracteres con la palabra o patrón que estamos buscando. Retorna un valor booleano: true si encuentra la palabra y false en caso contrario.
  • hasPrefix: A este método le pasamos como parametro una cadena de caracteres con la palabra o patrón que estamos buscando al inicio del texto. Retorna un valor booleano: true si el texto comienza con la palabra y false en caso contrario.
  • hasSuffix: A este método le pasamos como parametro una cadena de caracteres con la palabra o patrón que estamos buscando al final del texto. Retorna un valor booleano: true si encuentra la palabra al final del texto y false en caso contrario.

Con el método contains podemos detectar patrónes al inicio, en el medio como y al final del texto. Solo utilizamos hasPrefix y hasSuffix cuando necesitamos la certeza de que cierta palabra se encuentra al inicio o al final.

El uso de estos métodos es bien sencillo, veamos un ejemplo:

let name = "PhD. Charlie Root"

if name.hasPrefix("PhD.") {
    
    print("Info: Eres PhD, te necesitamos!")
    
} // if

let currentCarToPayTax = "Chevrolet Cruze, 2010"

if currentCarToPayTax.hasSuffix("2010") {
    
    print("Warning: Los coches de 2010 y anteriores págan un impuesto mayor al medio ambiente.")
    
} // if

La salida en pantalla:

Info: Eres PhD, te necesitamos!
Warning: Los coches de 2010 y anteriores págan un impuesto mayor al medio ambiente.

El caso de contains es muy similar, veamos:

let nuevoComentario = """

Hola gusano de los cojone',

Me cago en to' tus muertos, eres un mierda hoy y siempre.

Kotlin es mejor que Swift y Flutter mejor que ambos.

Tu hater número uno!

"""

let meanWords = ["gusano", "cago", "mierda", "kotlin", "flutter", "capitalista"]

var meanWordsFound = 0

print("Analizando nuevo comentario...\n")

meanWords.map { word in
    
    if nuevoComentario.lowercased().contains(word) {
        
        print("Coincidencia: \"\(word)\"")
        
        meanWordsFound += 1
        
    } // if

} // map

if meanWordsFound > 0 {
    
    print("\nSe han encontrado \(meanWordsFound) palabras clasificadas como hate, comentario movido a revisión!")
    
} else {
    
    print("\nSe han encontrado \(meanWordsFound) palabras clasificadas como hate, comentario aceptado!")
    
} // else

Este ejemplo es un poco más complejo a favor de que sea más entretenido y realista, no porque el uso de contains lo demande.

Declaramos un arreglo de nombre meanWords con las palabras que vamos a buscar dentro de cada nuevo comentario. Luego iteramos a través de cada una de estas palabras, y en cada ciclo de map pasamos la palabra en cuestión al método contains, no sin antes poner en minúsculas el texto entero ya que contains es case-sensitive, es decir que para él «Kotlin» no es lo mismo que «kotlin«, la letra inicial mayuscula diferencia ambas palabras.

Cada vez que encontramos una coincidencia lo imprimimos en pantalla y aumentamos el contador (meanWordsFound) en 1. Al final si el contador es mayor a cero el comentario se envía a revisión y de lo contrario se aprueba. La lógica del código es bien simple.

La salida en pantalla:

Analizando nuevo comentario...

Coincidencia: "gusano"
Coincidencia: "cago"
Coincidencia: "mierda"
Coincidencia: "kotlin"
Coincidencia: "flutter"

Se han encontrado 5 palabras clasificadas como hate, comentario movido a revisión!

Otro métodos y propiedades interesantes

Acabamos de ver el método lowercased pero hay otros muy similares a este que son igual de interesantes y útiles:

  • uppercased: Este método nos devuelve todo el texto en mayusculas sin modificar el original.
  • lowecased: Este método nos devuelve todo el texto en minusculas sin modificar el original.
  • capitalized: Esta propiedad nos devuelve el texto con cada palabra comenzando por una letra inicial mayuscula.

Veamos un ejemplo:

var someString = "Me gusta programar."

print(someString.uppercased())      // texto en mayúsculas
print(someString.lowercased())      // texto en minúsculas
print(someString.capitalized)       // primera letra de cada palabra en mayúsculas

La salida en pantalla:

ME GUSTA PROGRAMAR.
me gusta programar.
Me Gusta Programar.

Conclusiones

Estas son las funcionalidades más comunes y útiles que nos ofrece el tipo de dato String. Pero no son todas, existen algunas otras que siempre pueden conocer accediendo a la documentación oficial.

Falta aún mucho por aprender en nuestro camino a convertirnos en iOS Developer. Suscríbete a nuestra lista de correo y síguenos en nuestras redes sociales. Mantente al tanto de todas nuestras publicaciones.

Espero que todo cuanto se ha dicho aquí, de una forma u otra le haya servido de aprendizaje, de referencia, que haya valido su preciado tiempo.

Este artículo, al igual que el resto, será revisado con cierta frecuencia en pos de mantener un contenido de calidad y actualizado.

¡Cualquier duda o sugerencia, ya sea errores a corregir o ejemplos a añadir, será más que bienvenida, necesaria!

Deja una respuesta

Su dirección de correo electrónico no será publicada.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Este sitio web utiliza cookies para mejorar su experiencia. Asumiremos que está de acuerdo con esto, pero puede optar por no participar si lo desea. Aceptar Leer Más

RECIBE CONTENIDO SIMILAR EN TU CORREO

RECIBE CONTENIDO SIMILAR EN TU CORREO

Suscríbete a nuestra lista de correo y mantente actualizado con las nuevas publicaciones.

Se ha suscrito correctamente!