Variables de texto

En Javascript y en el mundo del desarrollo web, una de las tareas que más solemos hacer es manejar cadenas de texto y realizando tareas con ellas. Por lo tanto, tenemos que familiarizarnos con el tipo de dato String.

¿Qué es un string?

En programación, cuando hablamos de una varible que posee información de texto, decimos que su tipo de dato es String. En Javascript, es muy sencillo crear una variable de texto, hay dos formas de hacerlo:

Constructor Descripción
String new String(s) Crea un objeto de texto a partir del texto s pasado por parámetro.
String 's' Simplemente, el texto entre comillas. Notación preferida.

Los String son tipos de datos primitivos, y como tal, es más sencillo utilizar los literales que la notación con new. Para englobar los textos, se pueden utilizar comillas simples ', comillas dobles " o backticks ` (ver más adelante).

Aunque es posible utilizar comillas simples o comillas dobles en los String, se recomienda decantarse por uno de los dos estilos y no mezclarlos. Muchas empresas o equipos de desarrollo tienen guías de estilos para delimitar cuál utilizar.

A continuación, un ejemplo de declaración de variables de texto en Javascript:

// Literales
var texto1 = '¡Hola a todos!';
var texto2 = "Otro mensaje de texto";

// Objeto
var texto1 = new String('¡Hola a todos!');
var texto2 = new String("Otro mensaje de texto"); 

A diferencia de otros lenguajes de programación, que separan el tipo de dato String (cadena de texto) del tipo de dato char (un solo carácter), Javascript los mantiene a ambos dentro del tipo de dato String, por lo que una variable, aunque sólo contenga un carácter, sigue siendo un String.

Propiedades

Al crear una variable con contenido de texto, o sea un String, automáticamente, esa variable pasa a tener a su disposición todas las propiedades y métodos disponibles para este tipo de dato, por lo que podemos utilizarlos en nuestro código como iremos viendo a continuación.

Propiedad Descripción
Number .length Devuelve el número de carácteres de la variable de tipo string en cuestión.

En el caso de los strings, solo tenemos una propiedad, .length, que devuelve el tamaño de la variable de texto en cuestión. Nótese en los siguientes ejemplos que se han utilizado String directamente, sin necesidad de guardarlos en una variable antes:

'Hola'.length;     // 4
'Adiós'.length;    // 5
''.length;         // 0
'¡Yeah!'.length;   // 6

Pero las características más interesantes de los strings se encuentran en los métodos de dicho tipo de dato. Ten en cuenta que, en las variables de texto, los métodos se ejecutan sobre el propio texto del String, devolviendo información modificada a partir de este. Vamos a dar un repaso a los métodos que existen.

Métodos de posiciones

En primer lugar existen varios métodos que permiten darnos información sobre la posición o ubicación que ocupa un determinado carácter o texto. Esta posición también suele denominarse índice. Veamos detalladamente dicho métodos:

Método Descripción Oper.
String .charAt(pos) Devuelve el carácter en la posición pos de la variable. []
String .concat(str1, str2...) Devuelve el texto de la variable unido a str1, a str2... +
Number .indexOf(str) Devuelve la primera posición del texto str.
Number .indexOf(str, from) Idem al anterior, partiendo desde la posición from.
Number .lastIndexOf(str, from) Idem al anterior, pero devuelve la última posición.

El método .charAt(pos) nos permite comprobar que carácter se encuentra en la posición pos del texto. Este método devolverá un String con dicho carácter. En caso de pasarle una posición que no existe o imposible (negativa), simplemente nos devolverá un String vacío. El valor por defecto de pos es 0.

No obstante, es preferible utilizar el operador [] para obtener el carácter que ocupa una posición, ya que es más corto y rápido de utilizar y mucho más claro. La diferencia respecto a charAt() es que el operador [] devuelve Undefined si en esa posición no existe ningún carácter.

'Manz'.charAt(0);   // 'M'
'Manz'.charAt(1);   // 'a'
'Manz'.charAt(10);  // ''
'Manz'[0];          // 'M'
'Manz'[1];          // 'a'
'Manz'[10];         // undefined

El método .concat(str1, str2...) permite concatenar (unir) los textos pasados por parámetros al de la propia variable. Al igual que el método anterior, es preferible utilizar el operador +, ya que es mucho más rápido y legible. Mucho cuidado con utilizar el operador +, ya que depende de los tipos de datos con los que se usen puede producir un efecto diferente. El operador + usado con String realiza concatenaciones, mientras que usado con Number realiza sumas.

'Manz'.concat('i', 'to');   // 'Manzito'
'Manz' + 'i' + 'to';        // 'Manzito'
'Manz' + 4 + 5;             // 'Manz45'
10 + 5 + 4 + 5;             // 24

Por último, nos queda el método indexOf(str, from), que es la función opuesta a charAt(). La función indexOf(str) buscará el subtexto str en nuestra variable y nos devolverá un Number con la posición de la primera aparición de dicho subtexto. En caso de no encontrarlo, devolverá -1. El parámetro from es opcional, y es la posición en la que empezará a buscar, que por defecto (si no se suministra) es 0.

'LenguajeJS, página de Javascript'.indexOf('n');         // 2
'LenguajeJS, página de Javascript'.indexOf('n', 3);      // 16
'LenguajeJS, página de Javascript'.indexOf('n', 17);     // -1
'LenguajeJS, página de Javascript'.lastIndexOf('n');     // 16
'LenguajeJS, página de Javascript'.lastIndexOf('n', 3);  // 2

El método lastIndexOf(str, from) funciona exactamente igual que el anterior, sólo que realiza la búsqueda de la última aparición en lugar de la primera aparición.

Métodos para búsquedas

Los siguientes métodos se utilizan para realizar búsquedas o comprobaciones de subtextos en el texto de un String:

Método Descripción
Boolean .startsWith(str, from) Comprueba si el texto comienza por str desde la posición from.
Boolean .endsWith(str, to) Comprueba si el texto hasta la posición to, termina por str.
Boolean .includes(str, from) Comprueba si el texto contiene el subtexto str desde la posición from.
Number .search(regex) Busca si hay un patrón que encaje con regex y devuelve la posición.
Array .match(regex) Idem a la anterior, pero devuelve las coincidencias encontradas.

Por ejemplo, el método startsWith(str, from) devolverá true si la variable comienza por el texto proporcionado en str. Si además se indica el parámetro opcional from, empezará en la posición from del String. De la misma forma, el método endsWith() comprueba cuando un String acaba en str, y el método includes() comprueba si el subtexto dado está incluído en el String.

Algunos ejemplos:

'Manz'.startsWith('M');       // true ('Manz' empieza por 'M')
'Manz'.startsWith('a', 1);    // true ('anz' empieza por 'a')
'Manz'.endsWith('o');         // false ('Manz' no acaba en 'o')
'Manz'.endsWith('n', 3);      // true ('Man' acaba en 'n')
'Manz'.includes('an');        // true ('Manz' incluye 'an')
'Manz'.includes('M', 1);      // false ('anz' no incluye 'M')

Por otro lado, los métodos search() y match() realizan búsquedas más potentes y flexibles con RegExp. La diferencia de cada una es que, mientras el método search() devuelve la posición, matches() devuelve un Array con las coincidencias.

// La expresión regular /o/g busca globalmente las "o" en el texto

'Hola a todos'.search(/o/g);   // 1, porque la primera "o" está en la posición 1
'Hola a todos'.match(/o/g);    // ['o', 'o', 'o'], las 3 "o" que encuentra

Las expresiones regulares permiten realizar cosas mucho más avanzadas que las que se muestran en este ejemplo, por lo tanto, las abordaremos en temas posteriores.

Métodos para transformar

En Javascript podemos utilizar algunos métodos para modificar un String realizando alguna operación de transformación. En esta tabla tenemos dichos métodos:

Método Descripción
String .repeat(n) Devuelve el texto de la variable repetido n veces.
String .toLowerCase() Devuelve el texto de la variable en minúsculas.
String .toUpperCase() Devuelve el texto de la variable en mayúsculas.
String .trim() Devuelve el texto sin espacios a la izquierda y derecha.
String .trimStart() Devuelve el texto sin espacios a la izquierda.
String .trimEnd() Devuelve el texto sin espacios a la derecha.
String .replace(str|regex, newstr) Reemplaza la primera aparición del texto str por newstr.
String .replace(str|regex, func) Idem a la anterior, pero reemplazando por la devolución de func.
String .substr(ini, len) Devuelve el subtexto desde la posición ini hasta ini+len.
String .substring(ini, end) Devuelve el subtexto desde la posición ini hasta end.
String .slice(ini, end) Idem a .substr() con leves diferencias.
Array .split(sep|regex, limit) Separa el texto utilizando sep como separador, en limit fragmentos.
String .padStart(len, str) Rellena el principio de la cadena con str hasta llegar al tamaño len.
String .padEnd(len, str) Rellena el final de la cadena con str hasta llegar al tamaño len.

El método repeat(n) devuelve como String el texto repetido n veces. Por otro lado, los métodos toLowerCase() y toUpperCase() devuelven el texto convertido todo a minúsculas o todo a mayúsculas respectivamente:

'Na'.repeat(5);         // 'NaNaNaNaNa'
'MANZ'.toLowerCase();   // 'manz'
'manz'.toUpperCase();   // 'MANZ'
'    Hola  '.trim();    // 'Hola'

Por último, el método trim(), informalmente traducido como «afeitar» se encarga de devolver el texto eliminando los espacios sobrantes que hay a la izquierda o a la derecha del texto (y sólo esos, nunca los que hay entre palabras). De la misma forma, trimStart() y trimEnd() realizan la misma tarea sólo a la izquierda y sólo a la derecha respectivamente.

Reemplazar textos

Uno de los métodos más interesantes de transformación de String es el replace(str, newstr). Su funcionalidad más básica, como se ve en el primer ejemplo, se trata de devolver el texto en cuestión, reemplazando el texto str por newstr (¡y solo la primera aparición!):

'Amigo'.replace('A', 'Ene');    // 'Enemigo'
'Dispara'.replace('a', 'i');    // 'Dispira' (sólo reemplaza la primera aparición)
'Dispara'.replace(/a/g, 'i');   // 'Dispiri' (reemplaza todas las ocurrencias)

Si lo que nos interesa es reemplazar todas las apariciones, tendremos que hacer uso de las expresiones regulares, que veremos en temas posteriores a este. A grandes rasgos, en el tercer ejemplo anterior, en lugar de indicar el string 'a' indicamos la expresión regular /a/g que buscará todas las apariciones de a de forma global (todas las ocurrencias).

Además, el método replace() nos permite indicar, como segundo parámetro una Function en lugar de un String, permitiendo utilizar dicha función para realizar un proceso más complejo al reemplazar, en lugar de simplemente reemplazar por un String. Sin embargo, para aprender a utilizar esta funcionalidad, antes tendremos que aprender los callbacks, que veremos también más adelante.

Extraer subtextos

Otras de las operaciones fundamentales de los String es la posibilidad de extraer pequeños fragmentos de texto de textos más grandes. Para ello tenemos dos aproximaciones para realizarlo: con el método substr() o con el método substring().

En el primer caso, el método substr(ini, len) nos solicita dos parámetros, ini, que es la posición inicial del subtexto, y len, que es el tamaño o longitud que tendrá el texto. De esta forma, substr(2, 4) extrae el fragmento de texto desde la posición 2 y desde esa posición 4 posiciones más. En el caso de omitirse el parámetro len, se devuelve el subtexto hasta el final del texto original:

'Submarino'.substr(3);          // 'marino' (desde el 3 en adelante)
'Submarino'.substr(3, 1);       // 'm'      (desde el 3, hasta el 3+1)
'Submarino'.substring(3);       // 'marino' (desde el 3 en adelante)
'Submarino'.substring(3, 6);    // 'mar'    (desde el 3, hasta el 6)

Por otro lado, el método substring(ini, end) extrae el fragmento de texto desde la posición ini hasta la posición end. De igual forma al anterior, si se omite el parámetro end, el subtexto abarcará hasta el final del texto original.

Crear Arrays a partir de textos

Otro método muy útil es split(sep), un método que permite dividir un String por el substring sep como separador, devolviendo un array con cada una de las partes divididas. Es muy útil para crear arrays, o dividir en diferentes secciones textos que tienen separadores repetidos como podrían ser comas, puntos o pipes:

'1.2.3.4.5'.split('.');         // ['1', '2', '3', '4', '5'] (5 elementos)
'Hola a todos'.split(' ');      // ['Hola', 'a', 'todos'] (3 elementos)
'Código'.split('');             // ['C', 'ó', 'd', 'i', 'g', 'o'] (6 elementos)

En el último ejemplo, el separador es una cadena vacía, es decir, «ningún carácter». Si le indicamos a split() que separe por «ningún carácter», lo que hace es hacer una división en su unidad mínima, carácter por carácter.

En el tema de los arrays veremos un método llamado join() que es justo el opuesto de split(). Si split separa un string en varios y los mete en un array, join une varios elementos de un array añadiéndole un separador y lo convierte en string.

Relleno de cadenas

Otra transformación interesante con los String es la resultante de utilizar métodos como padStart(len, str) o padEnd(len, str). Ambos métodos toman dos parámetros: len la longitud deseada del String resultante y str el carácter a utilizar como relleno.

El objetivo de ambas funciones es devolver un nuevo String con la información original existente, pero ampliando su tamaño a len y rellenando el resto con str, al principio si se usa padStart() o al final si se usa padEnd():

'5'.padStart(6, '0');   // '000005'
'A'.padEnd(5, '·');     // 'A····'

Estos métodos resultan especialmente interesantes para formatear horas, como por ejemplo en el caso que queremos que las cifras menores a 10 aparezcan en formato 00 en lugar de 0.

Métodos Unicode

Unicode es el nombre por el que se conoce al sistema moderno de codificación de carácteres que se usa en informática. A grandes rasgos, cada carácter como podría ser la A, la B o cualquier otro, tiene su representación Unicode, que se basa en un código o code point.

Por ejemplo, el carácter A corresponde al código Unicode U+0041. Este 0041 realmente está en hexadecimal, por lo que 0x0041 en decimal sería igual a 65. Existen muchísimos códigos, ya que cualquier carácter existente, tiene su propio código Unicode. En Javascript, tenemos dos métodos interesantes relacionado con este tema:

Método Descripción
String String.fromCharCode(num) Devuelve el carácter del valor unicode indicado en num.
Number .charCodeAt(pos) Devuelve el valor unicode del carácter de la posición pos del texto.

El primero de ellos es un método estático, por lo que hay que escribir directamente String.fromCharCode() y no utilizarlo desde una variable. Para usar este método, le pasamos un num por parámetro, que indicará el número o código Unicode al que queremos hacer referencia, y el método nos devolverá un String con el carácter Unicode en cuestión:

String.fromCharCode(65);          // 'A' (65 es el código U+0041 en decimal)
String.fromCharCode(0x0041);      // 'A' (0x0041 es el código U+0041 en hexadecimal)
'A'.charCodeAt(0);                // 65
'A'.charCodeAt(0).toString(16);   // 41

Por otro lado, el método charCodeAt() es la operación inversa a String.fromCharCode() con algún extra. A charCodeAt(pos) le pasamos una posición con pos por parámetro. Esto buscará el carácter de la posición pos del String y nos devolverá su código Unicode (por defecto, en decimal). Si queremos pasarlo a otra base numérica, podemos hacer uso del método toString(base) indicando 16 como base.

Observa a continuación que, los famosos emojis (por ejemplo), son realmente una combinación de 2 códigos Unicode:

// El valor unicode del emoji 🐦 es (55357, 56358)
emoji = '🐦';
codigos = [];

for (var i = 0; i < emoji.length; i++)
  codigos.push(emoji.charCodeAt(i));

String.fromCharCode(...codigos);  // '🐦' (Usamos desestructuración, ver más adelante)

Observa que modificando el último código Unicode, podemos obtener diferentes emojis:

String.fromCharCode(55357, 56358);    // '🐦'
String.fromCharCode(55357, 56359);    // '🐧'
String.fromCharCode(55357, 56360);    // '🐨'
'\u0041';                             // 'A'
'\ud83d\udc28';                       // '🐨'

Una forma rápida de escribir carácteres Unicode es utilizando la secuencia de escape \u seguida del código Unicode en hexadecimal del caracter en cuestión, como se ve en los dos últimos ejemplos anteriores.

Interpolación de variables

En ECMAScript 6 se introduce una interesante mejora en la manipulación general de String, sobre todo respecto a la legibilidad de código.

Hasta ahora, si queríamos concatenar el valor de algunas variables con textos predefinidos por nosotros, teníamos que hacer algo parecido a esto:

var sujeto = 'frase';
var adjetivo = 'concatenada';
'Una ' + sujeto + ' bien ' + adjetivo;    // 'Una frase bien concatenada'

A medida que añadimos más variables, el código se hace bastante menos claro y más complejo de leer, especialmente si tenemos que añadir arrays, introducir comillas simples que habría que escapar con \' o combinar comillas simples con dobles, etc...

Para evitarlo, se introducen las backticks (comillas hacia atrás), que nos permiten interpolar el valor de las variables sin tener que cerrar, concatenar y abrir la cadena de texto continuamente:

var sujeto = 'frase';
var adjetivo = 'concatenada';
`Una ${sujeto} mejor ${adjetivo}`;        // 'Una frase mejor concatenada'

Esto es una funcionalidad muy simple, pero que mejora sustancialmente la calidad de código generado. Eso sí, recuerda que se introduce en ECMAScript 6, con todo lo que ello conlleva.

Manz
Publicado por Manz

Docente, divulgador informático y freelance. Escribe en Emezeta.com, es profesor en la Oficina de Software Libre de la Universidad de La Laguna y dirige el curso de Programación web FullStack de EOI en Tenerife (Canarias). En sus ratos libres, busca GIF de gatos en Internet.