Kitabı oku: «JavaScript: Guía completa», sayfa 5
Operar con cadenas de texto
Paar evitar tener que indicar la fecha a media noche y/o provocar posibles problemas, otro enfoque podría ser el de extraer de la cadena de texto que leemos en el campo de entrada las partes que representan el año, el mes y el día y después utilizarlas para crear la fecha, como hemos hecho en el capítulo anterior.
Puedes sustituir las líneas que hemos analizado y resaltado en negrita en el código anterior con las líneas siguientes:
const partesFecha = document.getElementById('fecha').value.split('-');const fechaEvento = new Date(partesFecha[0],partesFecha[1]-1,partesFecha[2] );console.log(fechaEvento);
Puedes encontrar este ejemplo en el archivo Formulario3_cadenas .html
La fecha se creará con el horario de medianoche (Figura 7.3).
Figura 7.3 – La fecha creada a medianoche.
Pero vamos a intentar entender cómo funciona este código. Todo se basa en el método split
que podemos aplicar a las cadenas de texto.
Split
requiere como argumento un separador y devuelve un array que contiene las partes de la cadena de texto a las cuales se aplica el método divididas según el separador. El separador, obviamente, no forma parte de las cadenas resultantes.
En nuestro caso, suponiendo que hayamos seleccionado como fecha el 25/12/2018, la cadena de texto inicial será:
"2018-12-25"
Por lo que nuestra separador será “-” y el array resultante contendrá los valores siguientes:
partesFecha[0] = 2018partesFecha[1] = 12partesFecha[2] = 25
Naturalmente, el valor para el mes disminuye en una unidad, dado que new Date
espera el mes expresado con un número del 0 al 11.
Gestores de eventos
En todos los ejemplos anteriores, hemos gestionado los eventos con gestores en línea de tipo onEvent
(
onClick
, onLoad
…); sin embargo, JavaScript dispone de otro tipo de sintaxis que prevé el uso de un listener, es decir, de una función que “escucha” (listen) esperando el evento que recibe como primer argumento y, si este se verifica, ejecuta el código que recibe en los argumentos siguientes.
Para probar esta sintaxis, vamos a escribir el primer ejemplo propuesto en este capítulo:
<form id=’miFormulario’><input type=”date” id=’fecha’><button type=”button” onclick=’leeFormulario()’ id=”boton”>Envía</button></form><p id=”output”></p><script>function leeFormulario() {document.getElementById(“output”).innerHTML = `La fecha seleccionada es: ${document.getElementById(‘fecha’).value}`;}document.getElementById("boton").addEventListener('click', leeFormulario)</script>
Puedes encontrar este ejemplo en el archivo Formulario_listener .html
Observa que hemos llamado el método addEventListener()
sobre el botón (identificado, como es habitual, mediante getElementById
) y, como primer argumento, le hemos pasado el evento que queremos interceptar, mientras que como segundo argumento le hemos pasado la función que se debe ejecutar si el evento se verifica.
Los nombres de los eventos que podemos pasar a addEventListener()
son iguales a los que hemos visto anteriormente, pero sin el prefijo
on
.
NOTA | El método addEventListener acepta un tercer argumento booleano que permite definir si el evento debe ser definido en fase de captura (true ) o en fase de bubbling (false ). Si elegimos gestionar el evento en fase de captura (o capturing), el evento primero es capturado por el elemento más externo y, después, difundido a los elementos internos. Pasa lo contrario con la gestión en fase de bubbling, donde el evento primero es capturado y gestionado por el elemento más interno y después se propaga a los elementos más externos. Este es el comportamiento predefinido, si no se asigna un valor al tercer argumento de addEventListener. |
Además de pasar una función, también es posible escribir directamente el código que se tiene que ejecutar tras la verificación del evento mediante una función anónima, como hemos hecho en el código siguiente:
<style>.colorPicker { width: 50px; height: 50px; float: left; margin: 5px; border-style: solid;}</style><div class="colorPicker" id="negro" style="background-color:black"></div><div class="colorPicker" id="blanco" style="background-color:white"></div><div style="clear:both;"></div><div id="texto" style="width:400px; height: 400px; border-style:solid">…</div><script>document.getElementById("negro").addEventListener('click', function () { document.getElementById("texto").style.backgroundColor = 'black'; document.getElementById("texto").style.color = 'white';});document.getElementById("blanco").addEventListener('click', function () { document.getElementById("texto").style.backgroundColor = 'white'; document.getElementById("texto").style.color = 'black';})</script>
Puedes encontrar este ejemplo en el archivo Formulario_listener1 .html
Si ejecutas este código en el navegador, podrás ver dos cuadros, uno blanco y otro negro (id=”negro” e id=”blanco”) y un espacio con texto (Figura 7.4).
Figura 7.4 – La página en el navegador.
Si haces clic sobre uno de los cuadros verás como cambia el color de fondo y el de los caracteres del área con el texto.
A los dos cuadros se ha añadido un listener (analizamos solo uno, puesto que el otro funciona de modo idéntico) que responde al evento click:
document.getElementById("blanco").addEventListener('click', function () { document.getElementById("texto").style.backgroundColor = 'white'; document.getElementById("texto").style.color = 'black';})
Al pulsar sobre el cuadro blanco, se ejecuta una función anónima que configura el fondo blanco para el área de texto y el color negro para sus caracteres.
Para realizar estas modificaciones, hemos utilizado las propiedades del objeto de Java-Script style
, que representa una instrucción de estilo para un objeto. Sus propiedades corresponden a las propiedades de estilo CSS.
También se necesita una función anónima cuando en el gestor del evento se desea llamar una función a la cual se pasan parámetros.
Modificamos el ejemplo anterior para tener una función que modifica el color de fondo y de los caracteres del área de texto. A esta función debemos pasarle los colores que deseamos utilizar.
Mostramos solo la parte <script>
del archivo, puesto que el resto no cambia respecto al ejemplo anterior:
<script>function configuraFondo(colorFondo, colorTexto) { document.getElementById("texto").style.backgroundColor = colorFondo; document.getElementById("texto").style.color = colorTexto;}document.getElementById("negro").addEventListener('click', function () { configuraFondo('black', 'white');});document.getElementById("blanco").addEventListener('click', function () { configuraFondo('white','black');})</script>
Puedes encontrar este ejemplo en archivo Formulario_listener2 .html
Para completar este ejemplo, añadimos el código que muestra un puntero con forma de mano cuando el ratón pasa por encima de los cuadros y le devuelve la forma clásica de flecha cuando el ratón se aleja de ellos: para ello, debemos utilizar los eventos mouseover
y mouseout
.
Antes de escribir los gestores para estos eventos, escribimos la función que queremos llamar cuando los eventos se verifican.
function configuraRaton(puntero) { document.body.style.cursor = puntero;}
Utilizamos la propiedad cursor
de
style
. El aspecto del puntero se pasará como parámetro cuando se llame la función en los gestores de los eventos:
document.getElementById("negro").addEventListener('mouseover', function () { configuraRaton('pointer');});document.getElementById("blanco").addEventListener('mouseover', function () { configuraRaton('pointer');})document.getElementById("negro").addEventListener('mouseout', function () { configuraRaton('auto');});document.getElementById("blanco").addEventListener('mouseout', function () { configuraRaton('auto');}
Los valores pasados a la función configuraRaton
son los valores que pueden ser aceptados por la propiedad cursor
. Nosotros hemos utilizado los más comunes: pointer
, que corresponde a la manita que señala los elementos activos y los vínculos, y auto
, que corresponde al puntero normal en forma de flecha blanca. Para todos los otros valores disponibles, puedes dirigirte a la página https://www.w3schools.com/jsref/prop_style_cursor.asp.
NOTA | Retomaremos este ejemplo y profundizaremos en él en el capítulo dedicado a this . |
En este capítulo, solo hemos hecho mención del uso de los listeners. Volveremos a hablar de ellos más adelante, en el capítulo dedicado a las funciones avanzadas y en el que también trataremos el elemento this
.
Expresiones regulares
Las expresiones regulares describen un patrón de caracteres y se pueden utilizar para verificar que el texto se ajusta a un modelo específico.
Temas tratados
•Creación de patrones
•Uso de expresiones regulares
•Probar si un elemento es ''
, null
, undefined
, false
, 0
o NaN
•Unir los valores de un array en una única cadena de texto
•forEach
para ejecutar un bucle sobre todos los elementos de un array
Las expresiones regulares describen un patrón de caracteres y pueden ser utilizadas para verificar que un texto se ajusta a un modelo específico.
Es decir, estas expresiones nos permiten verificar que un valor representa, como mínimo en su forma (verificar la sustancia es un poco más complicado), el dato que efectivamente se solicita.
Imagina un módulo que requiere proporcionar una dirección de correo electrónico. Antes de memorizar el dato, necesitamos estar seguros de que se trata efectivamente de una dirección de correo electrónico. Esto puede valer también para otros tipos de datos, como códigos fiscales o partidas de IVA.
Las expresiones también tienen otro uso, a saber, la posibilidad de manipular las cadenas basadas en estructuras predefinidas.
Para utilizar las expresiones regulares, es preciso definir un patrón o pattern, un modelo con el cual comparar la cadena de texto a verificar.
La convalidación de un dato insertado en un formulario, con la introducción en HTML5 del atributo pattern
, ha sido simplificada y ya no necesita código JavaScript.
En cualquier caso, HTML5, para la definición de los patrones de control, utiliza la sintaxis de las expresiones regulares de ECMAScript.
Por esta razón, todo cuanto expongamos en este capítulo es válido también para la validación de formularios HTML5.
Definir los patrones para las expresiones regulares
Antes de empezar con los ejemplos prácticos, queremos exponer los principios básicos con los cuales se construyen los patrones de las expresiones regulares, que después podremos dar por sabidos.
El concepto básico es que es preciso encontrar el modo de describir qué caracteres son aceptables en la expresión regular escrita (cifras, letras, caracteres especiales, etc.). Para ello, se pueden utilizar los símbolos mostrados en las tablas siguientes.
Tabla 8.1 – Clases de caracteres.
Carácter | Representa |
\d | Cualquier cifra del 0 al 9 |
\D | Cualquier carácter (letras, símbolos, pero no cifras) |
\w | Cualquier carácter del alfabeto latino, mayúsculas o minúsculas, cifras y el guion bajo(A-Z, a-z, 0-9, _) |
\W | Caracteres especiales, no caracteres alfabéticos en minúscula o mayúscula, cifras, ni guiones bajos o espacios |
\s | Un carácter que indica un espacio (espacio, tabulación, retorno de carro, etc., traducible en blanco, CR, LF, FF, HT, VT) |
\S | Cualquier carácter, excepto aquellos que indican un espacio |
. | Cualquier carácter único |
\t | Un carácter de tabulación |
\r | Un retorno de carro (carriage return) |
\n | Nueva línea |
\v | Tabulación vertical |
\f | Form feed para enviar la página a la impresora y avanzar al módulo siguiente |
[\b] | Retroceso |
\0 | Carácter nulo |
\cX | Donde X es una letra de la A a la Z. Encuentra un carácter de control en una cadena de texto |
\ | Tiene dos usos:• indica que el carácter siguiente no debe ser tratado literalmente, sino que es un carácter especial en la expresión regular. \d no indica la letra “d” sino una cifra, como hemos visto anteriormente;• indica que un carácter que normalmente se utiliza como carácter especial es tratado literalmente. \. no indica un carácter único cualquiera como hemos visto anteriormente, sino el carácter “.” |
Tabla 8.2 – Conjunto de caracteres.
Carácter | Representa |
[...] | Cualquiera de los caracteres indicados entre los corchetes |
[^...] | Cualquier carácter, excepto los que se indican entre corchetes |
Tabla 8.3 – Alternativas.
Carácter | Representa |
x|y | Encuentra o x o y. De forma más general, | indica una alternativa entre lo que se encuentra a su derecha y a su izquierda |
Tabla 8.4 – Límites.
Carácter | Representa |
^ | Identifica el inicio de una cadena de texto. Por ejemplo,/^A/ identifica la primera “A” de “Alessanda”, pero no las siguientes |
$ | Identifica el final de una cadena de texto. Por ejemplo, /$o/ identifica la “o” de “perro” pero no de “mona” |
\b | Identifica los límites de una palabra, es decir, la posición en que un carácter (no especial) no es seguido o precedido por un carácter (no especial).Por ejemplo, /\bn/ identifica la “n” de “noche” o de “con”, pero no de “ángulo” |
\B | Identifica los límites sin palabra, a saber, los casos en que un carácter y el siguiente o el precedente son del mismo tipo (caracteres normales o caracteres especiales) |
Tabla 8.5 – Repeticiones.
Carácter | Representa |
{n} | El elemento precedente se repite n veces |
{n,} | El elemento precedente se repite n veces o más. En la práctica, n es el número mínimo de repeticiones |
{n,m} | El elemento precedente está repetido de un mínimo de n veces a un máximo de m veces |
* | El elemento precedente se repite 0 o más veces |
? | El elemento precedente se repite 0 o una vez |
+ | El elemento precedente se repite una o más veces |
Tabla 8.6 – Declaraciones.
Carácter | Representa |
x(?=y) | Identifica un carácter x solo si es seguido por un carácter y |
Las expresiones regulares permiten agrupar partes de caracteres para un posible uso posterior. El grupo se define como “capturing” si es recordado y si no, como “non capturing”.
Tabla 8.7 – Agrupación y almacenamiento
Carácter | Representa |
(x) | Identifica el grupo x y recuerda el grupo identificado |
\n | Donde n es un número entero positivo |
(?:x) | Identifica z, pero no lo recuerda |
Las banderas o flags se sitúan al final del patrón y modifican su comportamiento.
Tabla 8.8 – Flags.
Carácter | Representa |
g | Identifica todas las coincidencias del patrón y no se detiene en la primera |
i | No distingue entre mayúsculas y minúsculas |
m | Línea múltiple; trata los caracteres de inicio y fin (^ e $) como si trabajaran en varias líneas (es decir, identifica el inicio y el final de cada línea individual) |
u | El patrón es tratado como unicode. Presentado con ECMAScript 6 |
y | Ejecuta una búsqueda “sticky”, es decir, identifica el patrón solo a partir de la posición indicada en la propiedad lastIndex de la expresión regular. Presentado en ECMAScript 6 |
En JavaScript, los patrones pueden ser escritos según tres sistemas de notación.
Suponiendo que tenemos el patrón [aeiou]\d
y el flag g
, podemos escribir de una de las siguientes maneras:
•/patron/flags: let patron = /[aeiou]\d/g;
•new RegExp(patron[, flags]): let patron = new RegExp('[aeiou]\\d','g');
•RegExp(patron[, flags]): let patron = RegExp('[aeiou]\\d', 'g').
Observa que en la segunda y tercera solución, el patrón se escribe como una cadena de texto y, por tanto, para conseguir que el carácter \
asuma su significado de metacarácter y transforme el significado de d
(que no tiene que representar la letra d, sino cualquier número), debemos situar otra barra inclinada antes de la que transforma el d
: \\d
.
Esta práctica se denomina escape del carácter.
Una vez dicho esto, la primera solución nos parece la más inmediata y rápida, por lo que será la que adoptaremos en los ejemplos propuestos en este capítulo. Sin embargo, naturalmente, cada uno es libre de proceder como prefiera.
Aplicar expresiones regulares
Después de esta introducción/referencia, podemos pasar a aplicar las expresiones regulares en algunos ejemplos.
Podemos empezar aplicando a una expresión regular el método test()
para verificar si una cadena de texto se corresponde con un determinado patrón.
let texto = "ape5"let patron = /[aeiou]\d/g;let correspondeAPatron = patron.test(texto);console.log(correspondeAPatron);
Puedes encontrar este ejemplo en el archivo test .html
En este caso, en la consola leeremos true
, porque nuestro texto se corresponde con patron
, en cuanto contiene una vocal (uno de los caracteres entre corchetes) inmediatamente seguida de una cifra. Es decir, que la parte de la cadena que se corresponde con el patrón es “e5”.
Dejamos invariable el código y la cadena texto; vamos a modificar el patrón y ver los distintos resultados del método test.
Tabla 8.9 – Ejemplos de patrones.
Patrón | Resultado test | Notas |
/^[aeiou]\d | false | La búsqueda se realiza al inicio de la cadena (^) |
[aeiou]\d$ | true | La búsqueda se realiza al final de la cadena (^) |
/[aeiou]+\d/ | true | La vocal se busca una o más veces |
[aeiou]\\.\d | false | Entre la vocal y el número debe haber también un punto (\\. ). Observa que delante del carácter punto (.) hemos tenido que añadir un carácter de barra invertida (\), es decir, el carácter de escape que suspende el significado especial del carácter que lo sigue dentro de la expresión regular. En este caso, sirve para especificar que el carácter punto debe tener su significado literal y no su valor especial en la expresión regular (el punto indica un carácter cualquiera), es decir, su valor de metacarácter |
Seguimos con otro ejemplo similar, esta vez permitimos al usuario la inserción del texto que se desea verificar con una expresión regular: veremos si el texto insertado contiene alguna cifra.
<form><input type="text" id='texto'><button type="button" onclick='contieneNumeros()' id="boton">Comprueba si el texto insertado contiene números</button></form><p id="output"></p><script>function contieneNumeros() {let texto = document.getElementById('texto').value;let numeroPatron = /\d+/;let contieneNumeros = numeroPatron.test(texto);contieneNumeros ? document.getElementById('output').innerHTML = "El texto insertado contiene números" :document.getElementById('output').innerHTML = "El texto insertado NO contiene números"}</script>
Puedes encontrar este ejemplo en el archivo contieneNumeros .html
Observa el patrón que hemos utilizado:
let numeroPatron = /\d+/;
El patrón espera una cifra (\d
) repetida más de una vez (+
).
Extraer texto con una expresión regular
En los ejemplos anteriores, nos hemos limitado a verificar si un texto contenía una parte de cadena de texto que se corresponde con un patrón determinado.
Ahora queremos probar de extraer la parte de la cadena que se corresponde con una expresión regular.
Supongamos, por ejemplo, que deseamos extraer el código postal de una dirección:
let direccion = 'Plaza del Ayuntamiento, 08029 Barcelona'let cpPatron = /\d{5}/;let cp = direccion.match(cpPatron);console.log(cp);document.getElementById('output').innerHTML = `El CP e: ${cp}`;
Puedes encontrar este ejemplo en el archivo extraerCP .html
Para ello, utilizamos el método match()
de la cadena de texto (no de la expresión regular como pasaba con el método test()
) al cual pasamos como argumento el patrón de la expresión regular.
El patrón que utilizamos prevé una repetición de 5 cifras:
cpPatron = /\d{5}/;
El método match()
nos devuelve un array (Figura 8.1) que contiene las coincidencias encontradas. En este caso, la coincidencia identificada solo es una y, por tanto, podemos tranquilamente utilizar la variable que contiene el array para mostrar un valor en el <div>
output de nuestra página.
Figura 8.1 – La consola muestra que el método match() nos devuelve un array.
En nuestro ejemplo, hemos escrito la dirección de la cual se extraerá el CP directamente en el código. ¿Qué ocurriría si dejáramos que fuera el usuario quien insertara la dirección mediante un formulario y este insertara algo que no contuviera un CP?
<form><label for="texto">Escribe la dirección de la cual quieres extraer el CP:</label><input type="text" id='texto'><button type="button" onclick='extraeCP()' id="boton">Extrae CP</button></form><p id="output"></p><script>function extraeCP() {let direccion = document.getElementById('texto').value;let cpPatron = /\d{5}/;let cp = direccion.match(cpPatron);if (!cp) { document.getElementById('output').innerHTML = 'El texto insertado no contiene un CP';} else { document.getElementById('output').innerHTML = `El CP es: ${cp}`;}}</script>
Puedes encontrar este ejemplo en el archivo extraesCP1 .html
Si el usuario no inserta un CP (o algo que tenga forma de CP), el array CP tiene un valor null
(Figura 8.2).
Figura 8.2 – Si la cadena escrita por el usuario no contiene un conjunto de 5 cifras, el CP es null.
Es preciso verificar si CP no tiene un valor y, en ese caso, actuar en consecuencia.
Para ello, utilizamos el operador not
!
, que niega aquello que viene a continuación.
Es como si pidiéramos a la instrucción if
que verificara si CP no tiene un valor.
!cap
resulta true
si la variable cap
es ''
(cadena vacía), null
, undefined
, false
, 0
o NaN
(not a number); en nuestro caso, es null
.
Una vez realizada esta comprobación, podemos mostrar los mensajes oportunos.
En nuestro ejemplo anterior, hemos supuesto que la dirección insertada por el usuario contiene un único valor que corresponde a nuestra expresión regular. ¿Y si fueran dos, como un número postal de 5 cifras y después un CP? ¿Y si, por ejemplo, la dirección fuera “Calle del Triunfo, 07891 08029 Barcelona”?
function extraeCP() { let direccion = document.getElementById('texto').value; let cpPatron = /\d{5}/g; let cp = direccion.match(cpPatron); console.log(cp); if (!cp) { document.getElementById('output').innerHTML = 'El texto insertado no contiene un CP'; } else { document.getElementById('output').innerHTML = `El CP es: ${cp[cp.length-1]}`; }}
Puedes encontrar este ejemplo en el archivo extraerCP2 .html
En primer lugar, debemos modificar nuestro patrón, puesto que, de no ser así, match()
se detendrá durante la búsqueda en la primera coincidencia del patrón (Figura 8.3), es decir, en la parte que, en nuestro ejemplo, indica la dirección postal.
Figura 8.3 – La expresión regular identifica solo la primera coincidencia del patrón.
Es preciso añadir al patrón el flag g
, de manera que la búsqueda no se interrumpa y se identifiquen todas las coincidencias con nuestro patrón (Figura 8.4).
let capPattern = /\d{5}/g;
Figura 8.4 – Con el flag g se identifican todas las coincidencias del patrón.
Ahora ya solo nos queda por descubrir, leyendo la propiedad length
, cuántos elementos contiene el array cp
y, después, leer el valor situado en última posición (length-1
, dado que el índice del array empieza desde 0):
cp[cp.length-1]
Con el mismo principio, podemos realizar otro ejemplo. Supongamos que tenemos una caja de texto en la cual pedimos al usuario que escriba un código numérico (por ejemplo, una matrícula) que podría escribirse en distintos formatos: /(X 0000 XX, 0000 XXX, XX 0000 XX…
Nos interesa extraer la parte numérica y combinarla sin utilizar espacios ni separadores, eliminando cualquier otro carácter.
<form><label for='texto'>Escribe el número de tu matrícula:</label><input type="text" id='texto'><button type="button" onclick='envía()' id="boton">envía el dato insertado</button></form><p id="output"></p><script>function envia() { let codigoMatricula = document.getElementById('texto').value; let numerosPatron = /\d+/g; let numeros = codigoMatricula.match(numerosPatron); let matriculaCorrecta = numeros.join(''); document.getElementById('output').innerHTML = matriculaCorrecta;}</script>
Puedes encontrar este ejemplo en el archivo unificaNumeros .html
La única novedad de este código consiste en el método join()
del array, que nos permite unificar los elementos de un array en una única cadena. Nosotros hemos elegido no añadir ningún separador entre los elementos en la cadena resultante, por lo que hemos pasado al método
join
una cadena vacía (''
), pero es posible elegir cualquier separador, simplemente pasándolo como argumento de join
.
Ücretsiz ön izlemeyi tamamladınız.