Artículo original escrito por: Sonya Moisset
Artículo original: Two Ways to Check for Palindromes in JavaScript
Traducido y adaptado por: Sil Zubikarai

Este artículo está basado en la Certificación de freeCodeCamp,  Algoritmos de JavaScript y Estructuras de Datos, del desafío "Comprobador de palíndromos".

Un palíndromo es una palabra, frase, número, u otra secuencia de caracteres que se lee de la misma forma hacia adelante que hacia atrás. La palabra "palíndromo" fue usada por primera vez por el dramaturgo Inglés Ben Jonson en el siglo 17,  de las raíces griegas palin ("de nuevo") y dromos (camino, dirección). — fuente. Wikipedia.

En este artículo, voy a explicar dos acercamientos, el primero construido con funciones y el segundo usando un bucle for.

Desafío de Algoritmos

Regresa verdadero si la cadena de texto es un palíndromo. De otra forma, regresa falso.

Un palíndromo es una palabra o enunciado que es escrito de la misma forma de adelante y al-revés, ignorando la puntuación,  las mayúsculas, y el espaciado.

Nota. Vas a necesitar remover todos los caracteres no alfanuméricos  (puntuación, espacios y símbolos) y convertir todo en minúsculas para comprobar por palíndromos.

Pasaremos la cadena de texto en varios formatos, como "racecar", "RaceCar", y "race CAR" entre otros.
function palindrome(str) {
  return true;
}
palindrome("eye");

Casos de prueba proporcionados

  • palíndromo ("race car") debe regresar verdadero.
  • palíndromo ("not  a palidrome") debe regresar falso.
  • palíndromo("A man, a plan, a canal. Panama") debe regresar verdadero
  • palíndromo("never odd or even") debe regresar verdadero.
  • palíndromo("nope") debe regresar falso.
  • palíndromo("almostomla") debe regresar falso.
  • palíndromo("My age is 0, 0 si ega ym.") debe regresar verdadero.
  • palíndromo("1 eye for of 1 eye") debe regresar falso.
  • palíndromo(“0_0 (: /-\ :) 0–0”) debe regresar verdadero.

¿Qué expresión regular necesitaremos para pasar el último caso de prueba?

Las expresiones regulares son patrones usados para hacer coincidir combinaciones de caracteres de cadenas.

Cuando la búsqueda de una coincidencia requiere algo más que una coincidencia directa, el patrón incluye caracteres especiales.

 Para pasar el ultimo caso de prueda, podemos usar dos Expresiones Regulares:

/[^A-Za-z0–9]/g  or o

/[\W_]/g

\W elimina todos los caracteres no-alfanuméricos.

  • \W coincide con cualquier carácter que no sea palabra.
  • \W es el equivalente a  [^A-Za-z0-9_].
  • \W  coincide cualquier cosa que no esté entre los corchetes.

¿Qué significa esto?

[^A-Z] coincide cualquier cosa que no este encerrada entre A y Z 

[^a-z] coincide cualquier cosa que no este encerrada entre a y z

[^0-9]  coincide cualquier cosa que no este encerrada entre 0 y 9

[^_] coincide cualquier cosa que no este encerrada en _

Pero en nuestro caso, necesitamos palíndromo (“0_0 (: /-\ :) 0–0”) para regresar true, que significa  “_(: /-\ :)–”  tiene que coincidir.

Necesitaremos añadir "_" para pasar este caso de prueba especifico.

Ahora tenemos “\W_”

Necesitaremos también añadir la bandera g para  búsqueda global.


Finalmente tenemos “/[\W_]/g”
/[\W_]/g fue usado por puros propósitos demostrativos para mostrar como RegExp trabaja. /[^A-Za-z0-9]/g es el más sencillo RegExp a escoger.

1. Comprobar por palíndromos con funciones incorporadas

Para esta solución, usaremos varios métodos:

  • El método toLowerCase() para regresar el valor de la  cadena de llamada  convertida en minúsculas.
  • El método replace() para regresar la nueva cadena con algunas o todas las coincidencias de un patrón con un remplazo. Usaremos  un RexExp que hemos creado antes.
  • El método split() una cadena objeto en un arreglo de cadenas separando la cadena en sub cadenas.
  • El método reverse()  invierte un arreglo en su lugar. El primer elemento del arreglo se convierte en el último y el último en el primero.
  • El método join() junta todos los elemento de un arreglo en una cadena.
function palindrome(str) {
  // Paso 1. Pon en minuscula la cadena y usa el RexEXP para remover los caracteres no deseados en el.
  var re = /[\W_]/g; // or var re = /[^A-Za-z0-9]/g;
  
  var lowRegStr = str.toLowerCase().replace(re, '');
  // str.toLowerCase() = "A man, a plan, a canal. Panama".toLowerCase() = "a man, a plan, a canal. panama"
  // str.replace(/[\W_]/g, '') = "a man, a plan, a canal. panama".replace(/[\W_]/g, '') = "amanaplanacanalpanama"
  // var lowRegStr = "amanaplanacanalpanama";
     
  // Paso 2. Utiliza los métodos de encadenamiento con funciones integradas.
  var reverseStr = lowRegStr.split('').reverse().join(''); 
  // lowRegStr.split('') = "amanaplanacanalpanama".split('') = ["a", "m", "a", "n", "a", "p", "l", "a", "n", "a", "c", "a", "n", "a", "l", "p", "a", "n", "a", "m", "a"]
  // ["a", "m", "a", "n", "a", "p", "l", "a", "n", "a", "c", "a", "n", "a", "l", "p", "a", "n", "a", "m", "a"].reverse() = ["a", "m", "a", "n", "a", "p", "l", "a", "n", "a", "c", "a", "n", "a", "l", "p", "a", "n", "a", "m", "a"]
  // ["a", "m", "a", "n", "a", "p", "l", "a", "n", "a", "c", "a", "n", "a", "l", "p", "a", "n", "a", "m", "a"].join('') = "amanaplanacanalpanama"
  // So, "amanaplanacanalpanama".split('').reverse().join('') = "amanaplanacanalpanama";
  // And, var reverseStr = "amanaplanacanalpanama";
   
  //  Paso 3. Revisa si reverseStr es estrictamente igual a lorRegStr y regresa un BooLean
  return reverseStr === lowRegStr; // "amanaplanacanalpanama" === "amanaplanacanalpanama"? => true
}
 
palindrome("A man, a plan, a canal. Panama");

Sin comentarios:

function palindrome(str) {
  var re = /[\W_]/g;
  var lowRegStr = str.toLowerCase().replace(re, '');
  var reverseStr = lowRegStr.split('').reverse().join(''); 
  return reverseStr === lowRegStr;
}
palindrome("A man, a plan, a canal. Panama");

2. Revisa por un palíndromo con un bucle FOR

La media indexación (len/2) tiene beneficios cuando procesa grandes cadenas de texto. Revisamos el final de cada parte y dividimos el número de iteraciones dentro del bucle FOR por dos.

function palindrome(str) {
 //  Paso 1.La primera parte es igual que la anterior
 var re = /[^A-Za-z0-9]/g; // or var re = /[\W_]/g;
 str = str.toLowerCase().replace(re, '');

 // Paso 2. Crea el bucle FOR
 var len = str.length; // var len = "A man, a plan, a canal. Panama".length = 30
 
 for (var i = 0; i < len/2; i++) {
   if (str[i] !== str[len - 1 - i]) { // Siempre y cuando los caracteres de cada parte coincidad, el bucle FOR debera seguir.
       return false; // Cuando los caracteres ya no coinciden, false es regresado y salimos del bucle FOR.
   }
   /* Aqui len/2 = 15
      For each iteration: i = ?    i < len/2    i++    if(str[i] !== str[len - 1 - i])?
      1st iteration:        0        yes         1     if(str[0] !== str[15 - 1 - 0])? => if("a"  !==  "a")? // false
      2nd iteration:        1        yes         2     if(str[1] !== str[15 - 1 - 1])? => if("m"  !==  "m")? // false      
      3rd iteration:        2        yes         3     if(str[2] !== str[15 - 1 - 2])? => if("a"  !==  "a")? // false  
      4th iteration:        3        yes         4     if(str[3] !== str[15 - 1 - 3])? => if("n"  !==  "n")? // false  
      5th iteration:        4        yes         5     if(str[4] !== str[15 - 1 - 4])? => if("a"  !==  "a")? // false
      6th iteration:        5        yes         6     if(str[5] !== str[15 - 1 - 5])? => if("p"  !==  "p")? // false
      7th iteration:        6        yes         7     if(str[6] !== str[15 - 1 - 6])? => if("l"  !==  "l")? // false
      8th iteration:        7        yes         8     if(str[7] !== str[15 - 1 - 7])? => if("a"  !==  "a")? // false
      9th iteration:        8        yes         9     if(str[8] !== str[15 - 1 - 8])? => if("n"  !==  "n")? // false
     10th iteration:        9        yes        10     if(str[9] !== str[15 - 1 - 9])? => if("a"  !==  "a")? // false
     11th iteration:       10        yes        11    if(str[10] !== str[15 - 1 - 10])? => if("c" !==  "c")? // false
     12th iteration:       11        yes        12    if(str[11] !== str[15 - 1 - 11])? => if("a" !==  "a")? // false
     13th iteration:       12        yes        13    if(str[12] !== str[15 - 1 - 12])? => if("n" !==  "n")? // false
     14th iteration:       13        yes        14    if(str[13] !== str[15 - 1 - 13])? => if("a" !==  "a")? // false
     15th iteration:       14        yes        15    if(str[14] !== str[15 - 1 - 14])? => if("l" !==  "l")? // false
     16th iteration:       15        no               
    End of the FOR Loop*/
 }
 return true; // Ambas partes son estrictamente iguales, y regresa true => La cadena de texto es un palindromo.
}

palindrome("A man, a plan, a canal. Panama");

Sin comentarios:

function palindrome(str) {
 var re = /[^A-Za-z0-9]/g;
 str = str.toLowerCase().replace(re, '');
 var len = str.length;
 for (var i = 0; i < len/2; i++) {
   if (str[i] !== str[len - 1 - i]) {
       return false;
   }
 }
 return true;
}
palindrome("A man, a plan, a canal. Panama");

Espero que hayas encontrado esto de utilidad.

Puedes seguirme en Medium, Twitter, Github, y LinkedIn