Cadenas: trabajar con texto
En resumen: Una cadena (string) es texto, una secuencia de caracteres con índices desde 0: tiene una longitud y métodos para buscar, reemplazar, recortar, dividir en partes y comparar.
Problema
El código es correcto, pero no funciona
La tienda da un 10% de descuento con el código VERANO10. Una clienta lo copia del anuncio, pero lo escribe en minúsculas y sin querer pone un espacio delante:
const code = await ask("");if (code === "VERANO10") { console.log("10% de descuento");} else { console.log("Código no válido");}rl.close(); verano10Código no válidoPara una persona, el código es el mismo. Para el programa, verano10 y VERANO10 son textos distintos: el primero tiene un carácter más, y las letras son otras. Tienes que poder mirar dentro de un texto y arreglarlo.
La idea
El texto es una secuencia de caracteres
El texto son caracteres colocados uno detrás de otro: letras, cifras, espacios, signos. Cada carácter tiene un índice, como en un array. El primero tiene el índice 0.
const code = "VERANO10";console.log(code.length);console.log(code[0]);console.log(code[code.length - 1]);8V0code.lengthes el número de caracteres.code[0]es el carácter con índice 0. El último carácter tiene el índicelength - 1.
Aquí no hay un tipo aparte para un solo carácter (en Java y C# se llama char). Un carácter es un texto de longitud 1. Las comillas simples y las dobles hacen lo mismo: 'V' y "V" son el mismo texto.
const code = "VERANO10";console.log(code.at(-1));console.log(code[-1]);console.log(typeof code[0]);console.log(code[0].length);console.log('V' === "V");0undefinedstring1truecode.at(-1) es el último carácter: un índice negativo cuenta desde el final. Con corchetes esto no funciona: code[-1] da undefined.
Tanto en el texto como en el array, la longitud es length, sin paréntesis.
Míralo
Carácter a carácter
¿Cuántas cifras tiene el número de teléfono? Recorres los índices desde 0 hasta el último y miras cada carácter:
const phone = "0888 123 456";let digits = 0;for (let i = 0; i < phone.length; i++) { const c = phone[i]; if (c >= "0" && c <= "9") { digits++; }}console.log("Cifras: " + digits);Cifras: 10c >= "0" && c <= "9" funciona porque cada carácter tiene un código: un número en la tabla de caracteres. Los textos se comparan por los códigos de sus caracteres. Las cifras de "0" a "9" tienen códigos seguidos, y también las letras de "a" a "z".
Más precisamente, para curiosos
- No hay métodos ya hechos del tipo «¿es una cifra?». Para una cifra, comparas como arriba. Para una letra: un carácter es mayúscula si
c !== c.toLowerCase()(su forma en minúscula es distinta), y minúscula sic !== c.toUpperCase(). Esto funciona también con letras que no están en el alfabeto inglés, comoéoñ. "A".charCodeAt(0)da el código de un carácter, es decir, 65. Al revés,String.fromCharCode(66)es"B". Cuidado:"a" + 1no es un error, es el texto"a1".- Sin índice:
for (const c of phone)recorre directamente los caracteres del texto.
const c = "É";console.log(c >= "0" && c <= "9");console.log(c.toUpperCase() !== c.toLowerCase());console.log(c !== c.toLowerCase());console.log("é" !== "é".toUpperCase());console.log("A".charCodeAt(0), String.fromCharCode(66));console.log("a" + 1);let digits = 0;for (const ch of "0888 123 456") { if (ch >= "0" && ch <= "9") { digits++; }}console.log(digits);falsetruetruetrue65 Ba110Pruébalo
¿Qué carácter?
¿Qué imprimirá el programa?
const word = "Factura";console.log(word[3]);console.log(word.length);Los índices son F 0, a 1, c 2, t 3. El carácter con índice 3 es el cuarto: «t». La longitud es el número de todos los caracteres, 7. El último índice es 6.
La idea
Los métodos del texto
El texto trae métodos ya hechos: acciones que llamas con un punto después del texto. Este es el arreglo del código promocional:
const code = " verano10";const clean = code.trim().toUpperCase();console.log("[" + clean + "]");console.log(clean === "VERANO10");[VERANO10]truetrim() quita los espacios del principio y del final. toUpperCase() pone todas las letras en mayúscula. Los métodos se pueden encadenar uno tras otro: el primero devuelve un texto, y el segundo se llama sobre él.
Algunos más, sobre una dirección de correo:
const email = "lucia.garcia@correo.es";console.log(email.includes("@"));console.log(email.indexOf("@"));console.log(email.slice(0, email.indexOf("@")));console.log(email.replaceAll(".", " "));console.log(email.endsWith(".es"));true12lucia.garcialucia garcia@correo estrue| Método | Qué hace |
|---|---|
includes(x) |
si x está dentro |
indexOf(x) |
el índice donde aparece x por primera vez (-1 si no está) |
slice(a, b) |
una parte del texto |
replaceAll(x, y) |
cada x se reemplaza por y |
startsWith(x), endsWith(x) |
si empieza (termina) por x |
toLowerCase() |
todas las letras en minúscula |
Cuidado con replace: en JavaScript reemplaza solo la primera aparición. Para todas escribes replaceAll.
console.log("lucia.garcia@correo.es".replace(".", " "));console.log("lucia.garcia@correo.es".indexOf("#"));console.log("Casa".startsWith("C"));console.log("Casa".toLowerCase());lucia garcia@correo.es-1truecasaMás precisamente, para curiosos
slice(a, b) toma los caracteres desde el índice a hasta el índice b, sin b. Son b - a caracteres. Con un solo argumento toma todo hasta el final. Un índice negativo cuenta desde el final: slice(-2) son los dos últimos caracteres.
const date = "2026-10-24";console.log(date.slice(5, 7));console.log(date.slice(8));console.log(date.slice(-2));102424La idea
El texto no cambia
Hay una particularidad que al principio confunde a todo el mundo:
let name = "maria";name.toUpperCase();console.log(name);name = name.toUpperCase();console.log(name);mariaMARIALa segunda línea no hace nada visible. toUpperCase() no cambia name. Crea un texto nuevo en mayúsculas y lo devuelve. Nadie lo guarda, y se pierde.
Una vez creado, un texto no se puede cambiar. Se dice que es inmutable (immutable). Cada método que «cambia» un texto en realidad devuelve uno nuevo. Para guardarlo, lo asignas: name = name.toUpperCase();.
let name = "maria";name.toUpperCase();console.log(name);name = name.toUpperCase();console.log(name);Paso a paso, en palabras
- name guarda el texto «maria»: 5 caracteres con índices del 0 al 4.
- toUpperCase() no toca «maria». Crea un texto nuevo, «MARIA».
- Nadie guarda el texto nuevo, y se pierde.
- name sigue guardando «maria», y eso es lo que se imprime.
- Otro texto nuevo, «MARIA», pero ahora = lo guarda en name. El antiguo «maria» se descarta.
- Ahora name guarda «MARIA».
Más precisamente, para curiosos
- Tampoco puedes cambiar un carácter dentro de un texto con un índice.
name[0] = "M"en un script normal no dice nada: no hay error, peronamesigue siendo"maria". En un archivo conimport(un módulo), la misma línea detiene el programa conTypeError: Cannot assign to read only property '0' of string. Creas un texto nuevo, por ejemplo"M" + name.slice(1). - Cuando tienes muchos trozos, júntalos en un array y únelos todos de una vez con
join:
const parts = ["leche", "pan", "huevos"];console.log(parts.join(", "));leche, pan, huevosPruébalo
Encuentra el error
La usuaria escribe su correo con mayúsculas y espacios. El programa debería limpiarlo y dejarla entrar, pero dice «No existe ese usuario.». ¿En qué línea está el error?
Elige la línea con el error.
email.trim(); devuelve un texto nuevo sin los espacios, pero no se guarda en ningún sitio. email sigue teniendo los espacios. La corrección es email = email.trim();, igual que en la línea 2.
La idea
El texto en partes
A menudo un texto guarda varias cosas separadas por un signo: productos con una coma, palabras con un espacio. split lo divide en partes y devuelve un array de textos:
const list = "leche,pan,huevos,queso";const items = list.split(",");console.log("Productos: " + items.length);for (let i = 0; i < items.length; i++) { console.log((i + 1) + ". " + items[i]);}Productos: 41. leche2. pan3. huevos4. quesoEl separador no forma parte de los trozos. A partir de aquí trabajas con un array normal: longitud, índices, un bucle.
Así también se lee una línea entera de números desde el teclado: la divides y conviertes cada parte en un número. Es justo lo que te faltaba en la lección anterior, la de las tablas:
const parts = (await ask("")).split(" ");let sum = 0;for (const p of parts) { sum += Number(p);}console.log(sum);rl.close();42 38 51 47 60238Más precisamente, para curiosos
- Dos espacios seguidos dan una parte vacía
''entre ellos.split(/ +/)(uno o más espacios) lo resuelve. Lo que va entre las barras es una expresión regular, un patrón para texto. Si no,splitrecibe texto normal, ysplit(".")divide por un punto. - Lo contrario de
splitesitems.join(", "): une las partes con un separador.
console.log("a b".split(" "));console.log("a b".split(/ +/));console.log("a.b".split("."));console.log(["a", "b"].join(", "));[ 'a', '', 'b' ][ 'a', 'b' ][ 'a', 'b' ]a, bPruébalo
¿Es lo mismo?
En JavaScript, === compara el contenido de los textos, letra por letra. Pero una letra mayúscula y una minúscula son caracteres distintos. La entrada es Madrid:
¿Qué imprimirá el programa?
const city = await ask("");console.log(city === "Madrid");console.log(city === "madrid");console.log(city.toLowerCase() === "madrid");rl.close();city === "Madrid" es true: las letras son las mismas. "madrid" empieza con una «m» minúscula, que es otro carácter, así que es false. Si las mayúsculas y minúsculas no importan, compara los dos textos en minúscula: city.toLowerCase() === "madrid".
Más precisamente, para curiosos
También existe == con dos signos de igual. Primero convierte los dos lados a un mismo tipo y solo después compara, así que el texto "1" y el número 1 resultan iguales:
console.log("1" == 1);console.log("1" === 1);truefalseCompara siempre con ===.
Ejercicio
Nombres y palabras
Resuelve los ejercicios en tu editor. El texto se lee del teclado como una línea entera.
1. El nombre al revés. Lee un nombre e imprímelo de atrás hacia delante. Recorres los índices desde el último hasta 0 y añades los caracteres a un texto nuevo.
CarmennemraC2. Número de palabras. Lee una frase y cuenta las palabras. Entre las palabras puede haber más de un espacio, y puede haber espacios al principio y al final. Pista: una palabra empieza donde el carácter no es un espacio y el anterior sí lo es (o no hay ninguno antes).
Hoy es un día festivoPalabras: 53. Palíndromo. Un palíndromo se lee igual de delante hacia atrás que de atrás hacia delante. Los espacios y las mayúsculas no cuentan. Quita los espacios, pon las letras en minúscula y compara el primer carácter con el último, el segundo con el penúltimo, y así sucesivamente.
Anita lava la tinaEs un palíndromoPan con quesoNo es un palíndromoEjercicio
Comprobaciones y conteo
4. Contraseña segura. Pide una contraseña hasta que el usuario escriba una segura: al menos 8 caracteres, al menos una cifra, una mayúscula y una minúscula. Después de cada contraseña débil, di qué se pide. Pista: do-while y una comprobación de cada carácter: una cifra con c >= "0" && c <= "9", una mayúscula con c !== c.toLowerCase(), una minúscula con c !== c.toUpperCase().
cafecafe2026Cafe2026Contraseña:Contraseña débil: al menos 8 caracteres, una cifra, una mayúscula y una minúscula.Contraseña:Contraseña débil: al menos 8 caracteres, una cifra, una mayúscula y una minúscula.Contraseña:Contraseña aceptada.Más ejercicios
- Comas en vez de espacios. Lee una frase y reemplaza cada espacio por una coma.
Mañana nos vamos a Valencia→Mañana,nos,vamos,a,Valencia. - El nombre más largo. Lee nombres separados por comas e imprime el más largo.
Ana,Cristina,Pedro→Cristina. - Las vocales con asterisco. Reemplaza cada vocal (a, e, i, o, u) por
*, sea mayúscula o minúscula.Me gusta leer→M* g*st* l**r. - Frecuencia de las letras. Cuenta cuántas veces aparece cada letra en el texto, sin distinguir mayúsculas y minúsculas. Pista: un array de 26 contadores, uno para cada letra de
'a'a'z'(lañy las vocales con tilde quedan fuera de ese rango: de momento puedes no contarlas). El índice de la letracesc.charCodeAt(0) - "a".charCodeAt(0). Imprime solo las letras que aparecen. - Gráfico de caracteres. Como el ejercicio anterior, pero en lugar del número imprime esa cantidad de asteriscos:
a: ****. - Cuántas veces cada palabra. Lee una frase y, para cada palabra distinta, imprime cuántas veces aparece. Pista: divídela en palabras y, para cada palabra, comprueba si ya se contó antes en el array.
- Ordenar por longitud. Lee palabras separadas por espacios e imprímelas de la más corta a la más larga. Ordena el array como ordenabas números, pero compara las longitudes.
- Número de oraciones. Cuenta las oraciones de un texto: cada una termina con
.,!o?. Cuidado con...y?!: terminan una oración, no tres. - Paréntesis equilibrados. Comprueba si los paréntesis de un texto están equilibrados. Con un solo tipo de paréntesis basta un contador:
(suma 1,)resta 1. El contador nunca debe bajar de 0, y al final debe ser 0. Con tres tipos,(),[],{}, necesitas un array de caracteres donde guardas los paréntesis abiertos, y un contador de hasta dónde está lleno: en un paréntesis de cierre, el último abierto tiene que ser del mismo tipo.{[()]}está equilibrado,([)]no.
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: Operadores y aritmética · Condiciones · Bucles · Arrays
- Continúa en: Lanzar excepciones y crear las tuyas · Cadenas · Expresiones regulares · Expresiones regulares: grupos y reemplazo
- Ejercicios sobre el tema: Fundamentos del lenguaje