Cadenas
Una cadena es un texto: un nombre, un mensaje, una línea que lees de un fichero o que llega por la red. Se escribe entre comillas y se guarda en una variable como cualquier otro valor. Lo general de los tipos de datos está en Tipos de datos.
Las cadenas no necesitan use: sus métodos están siempre, y se llaman con un punto sobre una variable, como nombre.upper(). Una cadena no cambia nunca: cada método devuelve una cadena nueva y deja la original como estaba.
var nombre = "Ana"
var grito = nombre.upper()
println(grito) // ANA
println(nombre) // Ana
Las cadenas funcionan igual en Windows y en todas las placas.
Escribir cadenas
Una cadena va entre comillas dobles o simples. Dentro de unas puedes poner las otras. "" es la cadena vacía.
var saludo = "Hola"
var cita = 'Di "hola"'
var ingles = "It's"
var vacia = ""
println(cita) // Di "hola"
println(ingles) // It's
Dentro de las comillas, la barra \ empieza un escape:
| Escape | Qué pone en la cadena |
|---|---|
\n | Un salto de línea. Son dos caracteres: el retorno de carro y el salto de línea (CR LF). |
\r | Un retorno de carro (CR). |
\t | Un tabulador. |
\\ | Una barra. |
Ninguna otra combinación es un escape: la barra se queda en la cadena, con el carácter que la siga. "\"" no es una comilla: es una cadena de dos caracteres, la barra y la comilla. Para escribir comillas dobles, abre la cadena con comillas simples, y al revés.
Una cadena puede seguir en la línea siguiente del programa. Cada salto de línea del programa se convierte en un espacio:
var aviso = "Pulsa A para saltar
y B para disparar"
println(aviso) // Pulsa A para saltar y B para disparar
Leer los caracteres
texto[i] devuelve el carácter de la posición i, como una cadena de uno. La primera posición es la 0, y la última, texto.size() - 1:
var palabra = "gato"
println(palabra[0]) // g
println(palabra[palabra.size() - 1]) // o
- Una posición negativa o mayor que la última lanza
ERR_INDEX_OUT_OF_RANGE. No hay posiciones contadas desde el final. - La posición tiene que ser un entero. Con un decimal, aunque sea
1.0, lanzaERR_TYPE_MISMATCH.
Para recorrer una cadena, usa foreach, que da un carácter en cada vuelta, o un for con las posiciones:
var palabra = "gato"
foreach (var letra in palabra)
print(letra, " ")
end
println("")
for (var i = palabra.size() - 1; i >= 0; i--)
print(palabra[i])
end
println("")
g a t o
otag
Cambiar un carácter
texto[i] = "x" cambia el carácter de la posición i. Como las cadenas no cambian, en realidad se crea una cadena nueva y se guarda en la variable. Otra variable que tuviera el mismo texto se queda como estaba:
var a = "gato"
var b = a
a[0] = "p"
println(a) // pato
println(b) // gato
Solo cuenta el primer carácter de lo que asignas: a[1] = "XY" pone una X. Lo que asignas tiene que ser una cadena con algún carácter: con otra cosa, como un número, lanza ERR_TYPE_MISMATCH, y con una cadena vacía, ERR_INVALID_VALUE. En los dos casos la cadena se queda como estaba.
Sacar un trozo
No hay un método que saque un trozo de una cadena. Se hace con un bucle:
func trozo(texto, desde, hasta)
var resultado = ""
for (var i = desde; i < hasta; i++)
resultado = resultado + texto[i]
end
return resultado
end
var frase = "Hola mundo"
println(trozo(frase, 5, 10)) // mundo
Si el texto tiene un separador, como una coma, es más fácil partirlo con split.
Unir cadenas
+ une dos cadenas:
var nombre = "Ana"
var saludo = "¡Hola, " + nombre + "!"
println(saludo) // ¡Hola, Ana!
+ solo une una cadena con otra. Una cadena más un número, un booleano, nil o una lista lanza ERR_TYPE_MISMATCH, con el mensaje Unsupported operand types for operator '+'.:
var vidas = 3
try
var texto = "Vidas: " + vidas
catch (var e)
println(e.message) // Unsupported operand types for operator '+'.
end
Para unir un número, conviértelo antes en cadena con su método toString() (los métodos de los números están en Tipos de datos). Si solo quieres imprimirlo, no hace falta: print y println admiten varios argumentos y los escriben uno detrás de otro (ver Librería estándar).
var vidas = 3
var tiempo = 12.5
var linea = "Vidas: " + vidas.toString() + " Tiempo: " + tiempo.toString()
println(linea) // Vidas: 3 Tiempo: 12.5
println("Vidas: ", vidas) // Vidas: 3
- El
toString()de un decimal da como mucho 15 cifras:0.1 + 0.2sale0.3. Un decimal suelto enprintlnsale con las cifras justas para que sea el mismo número:0.30000000000000004. - Los booleanos no tienen
toString(): usa unifcon las dos cadenas. - Para unir todos los elementos de una lista, usa
join.
Comparar cadenas
== y != comparan el texto, carácter a carácter, y distinguen las mayúsculas de las minúsculas. Para comparar sin mirarlas, pasa antes las dos a minúsculas:
var a = "Hola"
var b = "hola"
println(a == b) // false
var la = a.lower()
var lb = b.lower()
println(la == lb) // true
<, >, <= y >= no comparan texto: entre dos cadenas distintas dan siempre false, y <= y >= dan true solo si son iguales. Para ordenar cadenas, mételas en una lista y usa sort().
Letras con tilde
Las cadenas guardan el texto en UTF-8: una letra con tilde, la ñ o un símbolo como € ocupan dos bytes o más, y los métodos cuentan bytes, no letras.
var palabra = "año"
println(palabra.size()) // 4
var mayusculas = palabra.upper()
println(mayusculas) // AñO
size()ylen()cuentan bytes, yfind()devuelve una posición en bytes.texto[i],foreachysplit("")van byte a byte: una ñ sale partida en dos trozos que no se pueden imprimir por separado.upper()ylower()solo cambian las letras de la A a la Z. Las letras con tilde y la ñ se quedan como están.isAlpha()eisAlnum()danfalsesi hay una letra con tilde o una ñ.==,contains(),count(),replace()ysplit()con un separador funcionan bien con cualquier texto.
Métodos
| Método | Qué hace | Devuelve |
|---|---|---|
size() | Cuenta los bytes. | Entero |
find(subcadena, n) | Busca una subcadena. | Entero: la posición, o -1 |
contains(subcadena) | Mira si la contiene. | true o false |
count(subcadena) | Cuenta cuántas veces aparece. | Entero |
startsWith(inicio) | Mira si empieza así. | true o false |
endsWith(final) | Mira si acaba así. | true o false |
lower() | Pasa a minúsculas. | Cadena nueva |
upper() | Pasa a mayúsculas. | Cadena nueva |
strip() | Quita los espacios de los dos lados. | Cadena nueva |
leftStrip() | Quita los espacios del principio. | Cadena nueva |
rightStrip() | Quita los espacios del final. | Cadena nueva |
replace(buscar, poner) | Cambia un texto por otro. | Cadena nueva |
split(separador) | Parte la cadena por un separador. | Lista de cadenas |
join(lista) | Une los elementos de una lista, con la cadena entre ellos. | Cadena nueva |
isAlpha() | Mira si todo son letras. | true o false |
isDigit() | Mira si todo son cifras. | true o false |
isAlnum() | Mira si todo son letras o cifras. | true o false |
toInt() | Convierte a entero. | Entero |
toFloat() | Convierte a decimal. | Decimal, o un valor de error |
toBool() | Convierte a booleano. | true o false |
Errores comunes a todos:
- Con más o menos argumentos de los suyos lanzan
ERR_INVALID_ARG_NUMBER, y con un argumento de otro tipo,ERR_TYPE_MISMATCH. - El nombre sin paréntesis (
texto.size) lanzaERR_INVALID_OPERATION, y un método que no existe,ERR_ATTRIBUTE_NOT_FOUND. - Son excepciones: se capturan con
tryycatch(ver Errores y excepciones).
texto.size()
Devuelve el número de bytes de la cadena: el número de letras si no tiene tildes. Es lo mismo que len(texto).
var nombre = "Ana"
var vacia = ""
println(nombre.size()) // 3
println(vacia.size()) // 0
texto.find(subcadena, n)
Busca subcadena y devuelve la posición donde empieza, contando desde 0, o -1 si no está. n es opcional: el número de la aparición que buscas. Sin él, busca la primera.
var frase = "Hola mundo"
println(frase.find("mundo")) // 5
println(frase.find("o")) // 1
println(frase.find("o", 2)) // 9
println(frase.find("x")) // -1
- Distingue las mayúsculas de las minúsculas.
- Con una subcadena vacía devuelve 0.
subcadenatiene que ser una cadena, yn, un entero. Si no, lanzaERR_TYPE_MISMATCH.nempieza en 1: con 0 o un número negativo lanzaERR_INVALID_VALUE.
texto.contains(subcadena)
Devuelve true si subcadena está en el texto. Distingue las mayúsculas, y con una subcadena vacía da true.
var frase = "Hola mundo"
println(frase.contains("mundo")) // true
println(frase.contains("Mundo")) // false
texto.count(subcadena)
Cuenta cuántas veces aparece subcadena, sin contar dos veces las letras que se solapan: en "banana", "ana" aparece una vez. Con una subcadena vacía devuelve 0.
var fruta = "banana"
println(fruta.count("a")) // 3
println(fruta.count("ana")) // 1
texto.startsWith(inicio)
Devuelve true si el texto empieza por inicio. Distingue las mayúsculas, y con "" da true.
var fichero = "nivel3.map"
println(fichero.startsWith("nivel")) // true
println(fichero.startsWith("Nivel")) // false
texto.endsWith(final)
Devuelve true si el texto acaba en final. Distingue las mayúsculas, y con "" da true.
var fichero = "nivel3.map"
println(fichero.endsWith(".map")) // true
println(fichero.endsWith(".MAP")) // false
texto.lower()
Devuelve el texto en minúsculas. Solo cambia las letras de la A a la Z: las letras con tilde y la Ñ se quedan como están.
var titulo = "ÁRBOL Y ÑU"
println(titulo.lower()) // Árbol y Ñu
texto.upper()
Devuelve el texto en mayúsculas. Solo cambia las letras de la a a la z.
var nombre = "Íñigo"
println(nombre.upper()) // ÍñIGO
texto.strip()
Quita del principio y del final los espacios, los tabuladores y los saltos de línea. Los de en medio se quedan.
var entrada = " hola mundo \n"
var limpia = entrada.strip()
println("[", limpia, "]") // [hola mundo]
texto.leftStrip()
Como strip(), pero solo por el principio.
var entrada = " hola "
println("[", entrada.leftStrip(), "]") // [hola ]
texto.rightStrip()
Como strip(), pero solo por el final.
var entrada = " hola "
println("[", entrada.rightStrip(), "]") // [ hola]
texto.replace(buscar, poner)
Devuelve el texto con cada aparición de buscar cambiada por poner. Si buscar no está, o es una cadena vacía, devuelve el mismo texto. Para quitar un texto, pon "" en poner.
var frase = "Hola mundo"
println(frase.replace("mundo", "JARU")) // Hola JARU
println(frase.replace("o", "0")) // H0la mund0
var hora = "12:30:05"
println(hora.replace(":", "")) // 123005
Los dos argumentos tienen que ser cadenas. Si no, lanza ERR_TYPE_MISMATCH.
texto.split(separador)
Parte el texto por cada aparición de separador y devuelve una lista con los trozos, sin el separador.
var csv = "rojo,verde,azul"
var colores = csv.split(",")
println(colores) // [rojo, verde, azul]
println(colores.size()) // 3
- Dos separadores seguidos, o uno al principio o al final, dan trozos vacíos:
"a,,b,"da cuatro trozos,"a","","b"y"". - Si el separador no está, la lista tiene un solo trozo: el texto entero. Una cadena vacía da una lista con una cadena vacía.
- Con
""de separador, parte el texto byte a byte (ver Letras con tilde). - Para partir en líneas un texto que has escrito en el programa, usa
"\n". Un texto que viene de fuera (de un fichero o de la red) puede traer los saltos de línea sin el retorno de carro, y entonces"\n"no lo parte: pártelo porchr(10)y quita a cada línea el retorno de carro que pueda llevar al final constrip().
separador.join(lista)
Une los elementos de lista en una cadena, con el texto sobre el que lo llamas entre uno y otro. Como un método no se puede llamar sobre una cadena escrita entre comillas, guarda antes el separador en una variable:
var colores = ["rojo", "verde", "azul"]
var coma = ", "
println(coma.join(colores)) // rojo, verde, azul
var nada = ""
println(nada.join(colores)) // rojoverdeazul
- Los elementos que no son cadenas se convierten: los números, como con
toString(); los booleanos, entrueofalse;nil, ennone; y una lista o un mapa, enObject. - Con una lista vacía devuelve
"". - El argumento tiene que ser una lista (un array no vale). Si no, lanza
ERR_TYPE_MISMATCH.
texto.isAlpha()
Devuelve true si todos los caracteres son letras de la a a la z, en mayúscula o en minúscula. Una cadena vacía, un espacio, una letra con tilde o una ñ dan false.
var a = "Jaru"
var b = "año"
println(a.isAlpha()) // true
println(b.isAlpha()) // false
texto.isDigit()
Devuelve true si todos los caracteres son cifras del 0 al 9. Un signo, un punto decimal o una cadena vacía dan false. Sirve para saber si un texto es un entero sin signo antes de convertirlo con toInt().
var a = "2026"
var b = "-12"
var c = "1.5"
println(a.isDigit()) // true
println(b.isDigit()) // false
println(c.isDigit()) // false
texto.isAlnum()
Devuelve true si todos los caracteres son letras de la a a la z o cifras. Un _, un espacio, una letra con tilde o una cadena vacía dan false.
var a = "nivel3"
var b = "nivel_3"
println(a.isAlnum()) // true
println(b.isAlnum()) // false
texto.toInt()
Convierte el texto en un entero.
var a = "42"
var b = "3.7"
var c = "0x1F"
println(a.toInt() + 1) // 43
println(b.toInt()) // 3
println(c.toInt()) // 31
- Admite espacios al principio, un signo, decimales (se queda con la parte entera, sin redondear:
"-3.7"da -3), hexadecimal con0xy exponente ("1e3"da 1000). - Si el texto no es un número, está vacío o lleva algo detrás del número, aunque sea un espacio, lanza
ERR_TYPE_MISMATCHcon el mensajeCan not convert '…' to a number. - Si el número, sin su parte decimal, no cabe en un entero (más de 2.147.483.647 o menos de -2.147.483.648), o es
infonan, también lanzaERR_TYPE_MISMATCH, con el mensajeCan not convert '…' to an integer: out of range (-2147483648 to 2147483647).
var texto = "12abc"
try
var n = texto.toInt()
println(n)
catch (var e)
println(e.message) // Can not convert '12abc' to a number.
end
texto.toFloat()
Convierte el texto en un decimal, con todas sus cifras: "3.14" da lo mismo que 3.14. Admite lo mismo que toInt().
var a = "2.5"
var b = "42"
println(a.toFloat() * 2) // 5
println(b.toFloat()) // 42
Si el texto no es un número, no lanza ninguna excepción: devuelve un valor de error, que se imprime como Error 7 (el número de ERR_TYPE_MISMATCH). try no lo captura. Los valores de error se cuentan en Errores y excepciones. Para saber si ha fallado, mira si type() del resultado da tError.
Si el texto puede no ser un número, conviértelo con JSON.parse(texto), del módulo JSON. Lee todas las cifras, aunque algún decimal puede salir distinto en la última, y, si el texto no se puede leer, lanza ERR_INVALID_VALUE, que try sí captura:
use JSON
var texto = "3.14"
try
var x = JSON.parse(texto)
var doble = x * 2
println(doble.toString()) // 6.28
catch (var e)
println("No es un número: ", texto)
end
texto.toBool()
Devuelve false si la cadena está vacía, y true con cualquier otro texto, también con "false" o "0".
var a = ""
var b = "false"
println(a.toBool()) // false
println(b.toBool()) // true
Para leer un "true" o un "false" escrito en un texto, compáralo:
var texto = "true"
var activo = (texto == "true")
println(activo) // true
Ejemplo completo
Este programa lee unas puntuaciones escritas como texto, como llegar ían de un fichero o de la red. Las limpia, descarta las que no son un número y las imprime ordenadas por nombre.
var datos = "ana:120, LUIS:95 , marta:200,pablo:abc"
var tabla = {}
foreach (var entrada in datos.split(","))
var partes = entrada.split(":")
var nombre = partes[0].strip()
var puntos = partes[1].strip()
if (puntos.isDigit()) then
tabla[nombre.lower()] = puntos.toInt()
else
println("No son puntos: ", nombre, " -> ", puntos)
end
end
var nombres = tabla.keys()
nombres.sort()
foreach (var n in nombres)
var linea = n.upper() + ": " + tabla[n].toString()
println(linea)
end
var coma = ", "
println("Jugadores: ", coma.join(nombres))
No son puntos: pablo -> abc
ANA: 120
LUIS: 95
MARTA: 200
Jugadores: ana, luis, marta
Trampas y problemas conocidos
-
Un método no se puede llamar sobre una cadena escrita entre comillas, ni se puede indexar.
"hola".upper()no compila (Expected identifier in method name.), y"hola"[0]compila, pero lanzaERR_TYPE_MISMATCHal ejecutarse. Guarda antes la cadena en una variable. Más en Sintaxis básica.var grito = "hola".upper() -
Una cadena más un número es un error al ejecutar: ver Unir cadenas.
-
<y>no ordenan texto: ver Comparar cadenas. -
size()cuenta bytes, yupper(),lower()eisAlpha()no conocen las tildes: ver Letras con tilde. -
"\n"son dos caracteres (CR LF): ver Escribir cadenas ysplit. -
toBool()de"false"estrue: vertoBool. -
toFloat()no lanza excepciones: vertoFloat. -
Fallos de la VM que conviene evitar, cada uno con su aviso:
finddesde la tercera aparición,rightStripcon una cadena de espacios,replacecon una cadena vacía, que se cuelga, y un número asignado atexto[i], que cierra la VM.
Todos los problemas conocidos de JARU, juntos, están en Problemas conocidos.