soy Kseso y esto EsCSS

Javascript con Furoya: buscar cadena de texto y lidiar con literalidad y concordancia

Tercer artículo y final de la serie de Furoya dedicados a detectar, con javascript puro, si en el contenido de un elemento hay o no una palabra clave y en función de ello actuar.
En este se centra en manejar aspectos sobre literalidad y concordancia entre la cadena buscada y su forma en el elemento. Entre otras lidiar con mayúsculas y minúsculas.
Los artículos previos de esta serie:
Cómo añadir estilos si en el contenido hay una palabra clave y
Filtrar filas por palabra clave contenida en sus celdas

Javascript con Furoya: buscar cadena de texto y lidiar con literalidad y concordancia

✎ 1
COLABORACIÓN AUTOR INVITADO
Javascript con Furoya: buscar cadena de texto y lidiar con literalidad y concordancia

A estas alturas, ya tenemos claro que es posible ubicar una palabra (una cadena de texto) dentro de un elemento HTML, pero vimos solamente una forma de hacerlo.

Por otro lado, la búsqueda es case sensitive, y si bien es lo lógico porque somos nosotros quienes debemos escribir el texto exactamente como lo queremos encontrar, también es cierto que algunos motores de búsqueda ya nos han malacostumbrado al "interpretar" nuestras inquietudes y corregir no sólo las minúsculas sino hasta las faltas de ortografía. Con su pésimo criterio y perjudicando a los que sí sabemos escribir correctamente, y pedimos justamente lo que estamos tipeando.

Vamos a dar un par de vueltas de tuerca más, para ver formas de enfrentar el problema de acertar a un texto independientemente de cómo se lo escriba.

Si nos encontramos con textos "fijos" que ya conocemos de antemano, y sabemos cómo están escritos, el método HTML es el más práctico: en vez de una lista de sugerencias en un input, usamos un select. Así no hay posibilidad de que prueben un texto no válido.

See the Pen Search. Case ignored, or not. (1) by solipsistaCP (@solipsistacp) on CodePen.

Dejo una explicación rápida, porque lo que se ve aquí son códigos ya conocidos.

  • Hay una lista y un selector que contiene todos las palabras posibles dentro de los ítems. Después de elegir una, se ejecuta una función con el botón "BUSCAR", que toma el valor que tenga en ese momento el <select> y lo guarda en una variable; en otra guarda la referencia a todos los elementos <li>, para que un bucle for los recorra uno a uno. Dentro de sus paréntesis tenemos una variable s que vale 0 (cero), un condicional por el que s debe ser menor que el total de elementos de la lista, y el antes visto s++ que suma 1 después de ejecutar lo que tenga el bucle entre sus llaves.
  • El método para detener este bucle funciona porque el length o total de nodos empieza a contar desde 1; como hay 5 li, misListas.length es igual a 5. Pero cada uno tiene un número de orden que empieza a contar desde 0; y entonces el primero es misListas[0], el segundo, misListas[1], el tercero es misListas[2], el cuarto es misListas[3] y el quinto y último, misListas[4]. Como el total siempre va a ser mayor al número del último ítem, usamos este método para frenar el bucle: cuando s llegue a 5 (y se pase) ya no va a ser menor que que el total de 5 (claro, va a ser igual), y for se detiene.
  • En cada vuelta, si no encontró la palabra, asigna al li un atributo de clase vacío (o sin class) y si lo halló, le pone el atributo con la clase verde.
Un detalle que van a notar es que no puse las llaves para if else. Es que si se usa en una sola línea —aunque no están de más— no son realmente necesarias. Al ver el ejemplo se las pueden imaginar.

Conversión a mayúsculas

Veamos otro caso en que el texto esté todo en mayúscula pero no sepamos con seguridad qué palabras contiene (como el ejemplo del cartel de salidas y llegadas), donde podemos valernos de un escript que corrija las cadenas ingresadas en minúscula.

Existe en CSS una propiedad text-transform:uppercase que hace eso, pero es solamente visual, muestra el texto en mayúsculas y el valor sigue siendo el tipeado, que es el que usa al final javascript.

Así que aprovechamos una función nativa para cadenas de texto que realmente convierte a mayúscula, y es toUpperCase()

<script> alert( "abcd".toUpperCase() ) /*devuelve ABCD*/ <script>

Aquí un ejemplo funcionando, apenas más complejo que el anterior.

See the Pen Search. Case ignored, or not. (2) by solipsistaCP (@solipsistacp) on CodePen.

La desventaja de permitir el tipeo del texto, en vez de ofrecerlo al usuario ya escrito, está en que si ingresan una letra o hasta un espacio, la búsqueda trabaja igual y devuelve sus aciertos; cuando pidan una "O" va a marcar los "UNO", "DOS", "CUATRO" Y "CINCO". Algo que en muchos casos no está mal, es una opción que se le da al usuario. Pero si ingresan un vacío, debería marcar todas (porque en toda string hay espacios vacíos, desde el comienzo de una palabra hasta entre caracteres), y ya no sé si eso es práctico.

Impedir campo vacío

El método HTML 5 para evitar que pase un campo vacío, es nuestro ya conocido atributo required

<input required="required">

La versión javascript sería un poco más compleja, porque el escript lo estamos haciendo nosotros en vez de usar el que viene en el navegador:

<form name="alfa"> <input onclick="(document.forms['alfa']['bravo'].value=='')? alert('¡noop!') : alert('¡see!')" type="button" value="BUSCAR"> <input type="Text" name="bravo"> </form>

Y ésta es una forma resumida, donde se pone un condicional usando operadores ternarios:

  • El signo de interrogación ? cierra la condición que en el documento haya un formulario de nombre 'alfa' con un elemento de nombre 'bravo' y que tenga un valor vacío y si se cumple, ejecuta lo que tenga inmediatamente a continuación, si no se cumple ejecuta lo que hay después de los dos puntos : que funcionan como un "else".
  • La sintaxis para apuntar al input que se ve en el condicional es una muy común en formularios, y no se usa en otras estructuras de DOM, donde ya vimos getElementByID() o querySelector(), entre otras.

Hay más recursos, que se pueden combinar. Hablamos de expresiones regulares, que se usan en un pattern="" HTML 5. Algo como esto solamente admite caracteres en mayúscula

<style> input:invalid {background: tomato; } </style> <input required="required" pattern="[A-Z]+">

Aunque en rigor de verdad, lo que admite son cualquier cantidad de caracteres que estén entre "A" y "Z" en el ASCII. Quiero decir, que excluyen la "Ñ" y las vocales acentuadas.

"Regular expressions" para "case insensitive"

En javascript las regular expressions se usan mucho, y vamos a ver un caso en que sirven para hacer búsquedas que les dé igual si la palabra está en mayúsculas o minúsculas.

See the Pen Search. Case ignored, or not. (3) by solipsistaCP (@solipsistacp) on CodePen.

Parece complicado, pero vamos a verlo por partes, y para que esté más cómodo, aquí va todo el código;

<!DOCTYPE html> <html lang="es-ar"> <head> <meta charset="utf-8" /> <script type="text/javascript"> function busca3(){ var misListas = document.querySelectorAll("li"); var miTexto = document.getElementById("texto3").value; //alert(miTexto) var miExpReg = new RegExp(miTexto,"i"); for(s=0; s<misListas.length; s++){ var miAcierto = misListas[s].textContent.search(miExpReg); //alert( (s+1) +". → "+ miAcierto ); if(miAcierto == -1) misListas[s].className = ""; else misListas[s].className = "verde"; } } </script> <style type="text/css"> li { list-style-position: inside; padding-left: .4em; font-weight: bold; } li.verde { background: linear-gradient(315deg, white, white .42em, transparent .43em, transparent 100%), linear-gradient(225deg, white, white .42em, lime .43em, lime 100%); background-size: 1.6em 100%; background-repeat: no-repeat; } #texto3:required:invalid + input { pointer-events: none; opacity: .3; /*cursor: not-allowed; */ } </style> </head> <body> <h1>Destaca elementos de lista si contienen al menos una vez la palabra buscada. Es <i>case insensitive</i>.</h1> <form> <ol> <li> UNO dos uno </li> <li> DOS tres </li> <li> TRES cuatro </li> <li> CUATRO cinco </li> <li> CINCO uNo </li> </ol> <input type="search" name="texto3" id="texto3" required="required" pattern="\w+" size="6" placeholder="Palabra"> <input type="button" onclick="busca3()" value="BUSCA"> </form> </body> </html>

En el body no hay novedades, salvo la expresión regular dentro del pattern para que solamente puedan ingresar uno o más caracteres alfanuméricos, aunque después se limita la cantidad a 6 con el atributo size.

En el JS ya tenemos una variable que llamamos miExpReg y contiene la primer sorpresa: un constructor para expresiones regulares. No siempre es necesario, pero a nosotros nos sirve para ver mejor cómo se asignan.

La sintaxis new RegExp(miTexto,"i") pone en la variable una expresion regular formada por el texto que hay escrito en el campo (a través de otra variable miTexto, seguido por una flag "i" que le dice al escript que debe comparar el texto de manera "insensitive case", ignorando si es mayúscula o minúscula. Una string común y corriente no tiene esas capacidades, por eso lo metemos en una regexp que nos da más juego para hacer comparaciones.

Entonces el mecanismo ya sería igual a otros ejemplos: se busca ítem a ítem con un bucle y donde aparezca un acierto se cambia la clase ... aunque falta algo.

Hasta ahora usamos el indexOf, que es un método para string o cadena de texto; y por lo tanto no funciona en regexp. Así que lo vamos a cambiar por otro que sí anda, como search(), que devuelve exactamente el mismo resultado (-1 ó un índice numérico positivo).

El CSS es principalmente decorativo, con una clase diferenciada para cuando aparezca nuestro texto en un ítem de lista. Lo más llamativo es un agregado, que permite "habilitar" o no el botón de búsqueda según la validación HTML. Algo que generalmente se hace con JS, pero hoy vamos a hacer honor a este blog, donde siempre aparecen CSS's raros.

Autoría

Furoya: Autor del artículo

Artículo original de Furoya.
La intención del autor con sus colaboraciones no es que los artículos sirvan para hacer un copy&paste de códigos sino que comprendas y aprendas la lógica y el cómo trabaja javaScript.
Y a partir de lo expuesto experimentes tú.
El autor del post y el editor del blog te animamos a que plantees tus dudas o reflexiones y que compartas tus realizaciones en base a lo expuesto en los comentarios. Recuerda que puedes incluir pens (ejemplos en Codepen.io) en ellos.