Ir al contenido
wannacode

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();
Entrada
verano10
Salida
Código no válido

Para 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]);
Salida
8
V
0
  • code.length es el número de caracteres.
  • code[0] es el carácter con índice 0. El último carácter tiene el índice length - 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");
Salida
0
undefined
string
1
true

code.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);
Salida
Cifras: 10

c >= "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 si c !== 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" + 1 no 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);
Salida
false
true
true
true
65 B
a1
10

Pruébalo

¿Qué carácter?

¿Qué imprimirá el programa?

const word = "Factura";
console.log(word[3]);
console.log(word.length);
Respuesta

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");
Salida
[VERANO10]
true

trim() 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"));
Salida
true
12
lucia.garcia
lucia garcia@correo es
true
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());
Salida
lucia garcia@correo.es
-1
true
casa
Má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));
Salida
10
24
24

La 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);
Salida
maria
MARIA

La 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
  1. name guarda el texto «maria»: 5 caracteres con índices del 0 al 4.
  2. toUpperCase() no toca «maria». Crea un texto nuevo, «MARIA».
  3. Nadie guarda el texto nuevo, y se pierde.
  4. name sigue guardando «maria», y eso es lo que se imprime.
  5. Otro texto nuevo, «MARIA», pero ahora = lo guarda en name. El antiguo «maria» se descarta.
  6. 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, pero name sigue siendo "maria". En un archivo con import (un módulo), la misma línea detiene el programa con TypeError: 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(", "));
Salida
leche, pan, huevos

Prué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.

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]);
}
Salida
Productos: 4
1. leche
2. pan
3. huevos
4. queso

El 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();
Entrada
42 38 51 47 60
Salida
238
Má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, split recibe texto normal, y split(".") divide por un punto.
  • Lo contrario de split es items.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(", "));
Salida
[ 'a', '', 'b' ]
[ 'a', 'b' ]
[ 'a', 'b' ]
a, b

Prué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();
Respuesta
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);
Salida
true
false

Compara 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.

Entrada
Carmen
Salida
nemraC

2. 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).

Entrada
Hoy es un día festivo
Salida
Palabras: 5

3. 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.

Entrada
Anita lava la tina
Salida
Es un palíndromo
Entrada
Pan con queso
Salida
No es un palíndromo

Ejercicio

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().

Entrada
cafe
cafe2026
Cafe2026
Salida
Contraseñ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 letra c es c.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

1. ¿Qué da "Casa".length?
2. ¿Qué hace la línea name.toUpperCase(); sola, sin asignación?
3. ¿Qué da "Sevilla" === "sevilla" en JavaScript?
4. ¿Qué diferencia hay entre 'a' y "a" en JavaScript?
5. ¿Qué da "lun,mar,vie".split(",")?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·