Esa fue una pregunta de la entrevista que no pude responder:
¿Cómo comprobar que una cadena es un palíndromo usando expresiones regulares?
ps Ya existe una pregunta " ¿Cómo verificar si la cadena dada es palíndromo? " y da muchas respuestas en diferentes idiomas, pero ninguna respuesta que use expresiones regulares.
regex
palindrome
Degvik
fuente
fuente
Respuestas:
La respuesta a esta pregunta es que "es imposible". Más específicamente, el entrevistador se pregunta si prestó atención en su clase de teoría computacional.
En su clase de teoría computacional aprendió sobre las máquinas de estados finitos. Una máquina de estados finitos se compone de nodos y aristas. Cada borde está anotado con una letra de un alfabeto finito. Uno o más nodos son nodos de "aceptación" especiales y un nodo es el nodo de "inicio". A medida que se lee cada letra de una palabra dada, atravesamos el borde dado en la máquina. Si terminamos en un estado de aceptación, decimos que la máquina "acepta" esa palabra.
Una expresión regular siempre se puede traducir a una máquina de estados finitos equivalente. Es decir, uno que acepta y rechaza las mismas palabras que la expresión regular (en el mundo real, algunos lenguajes regexp permiten funciones arbitrarias, estas no cuentan).
Es imposible construir una máquina de estados finitos que acepte todos los palíndromos. La prueba se basa en los hechos de que podemos construir fácilmente una cadena que requiera una cantidad arbitrariamente grande de nodos, es decir, la cadena
a ^ xba ^ x (p. ej., aba, aabaa, aaabaaa, aaaabaaaa, ....)
donde a ^ x es un x repetido. Esto requiere al menos x nodos porque, después de ver la 'b', tenemos que contar hacia atrás x veces para asegurarnos de que sea un palíndromo.
Finalmente, volviendo a la pregunta original, podría decirle al entrevistador que puede escribir una expresión regular que acepte todos los palíndromos que sean más pequeños que una longitud fija finita. Si alguna vez hay una aplicación del mundo real que requiera identificar palíndromos, es casi seguro que no incluirá los que son arbitrariamente largos, por lo que esta respuesta demostraría que puede diferenciar las imposibilidades teóricas de las aplicaciones del mundo real. Aún así, la expresión regular real sería bastante larga, mucho más larga que el programa equivalente de 4 líneas (ejercicio fácil para el lector: escriba un programa que identifique palíndromos).
fuente
>=1.9
) aquíSi bien el motor PCRE admite expresiones regulares recursivas (consulte la respuesta de Peter Krauss ), no puede usar una expresión regular en el motor ICU (como lo usa, por ejemplo, Apple) para lograr esto sin código adicional. Deberá hacer algo como esto:
Esto detecta cualquier palíndromo, pero requiere un bucle (que será necesario porque las expresiones regulares no pueden contar).
fuente
No es posible. Los palíndromos no están definidos por un lenguaje regular. (Mira, aprendí algo en teoría computacional)
fuente
Con Perl regex:
Aunque, como muchos han señalado, esto no puede considerarse una expresión regular si quieres ser estricto. Las expresiones regulares no admiten la recursividad.
fuente
/u
modificador ), o porque los caracteres del combinador. (reemplazar.
con la\X
secuencia de escape ).abababa
. No es posible hacer que funcione con recursividad para cada entrada cuando se utilizan motores de expresiones regulares basados en PCRE. Casimirs regex usa un enfoque diferente, usando iteración y estado mutable, y es bastante fascinante.Aquí hay uno para detectar palíndromos de 4 letras (por ejemplo: escritura), para cualquier tipo de personaje:
Aquí hay uno para detectar palíndromos de 5 letras (por ejemplo: radar), verificando solo letras:
Entonces parece que necesitamos una expresión regular diferente para cada longitud de palabra posible. Esta publicación en una lista de correo de Python incluye algunos detalles del por qué (autómatas de estado finito y lema de bombeo).
fuente
Dependiendo de qué tan seguro esté, le daría esta respuesta:
fuente
¡Sí , puedes hacerlo en .Net!
¡Puedes comprobarlo aquí ! ¡Es una publicación maravillosa!
fuente
StackOverflow está lleno de respuestas como "¿Expresiones regulares? No, no lo admiten. No pueden admitirlo".
La verdad es que las expresiones regulares ya no tienen nada que ver con las gramáticas regulares . Las expresiones regulares modernas presentan funciones como la recursividad y los grupos de equilibrio, y la disponibilidad de sus implementaciones es cada vez mayor (consulte los ejemplos de Ruby aquí, por ejemplo). En mi opinión, aferrarse a la vieja creencia de que las expresiones regulares en nuestro campo son cualquier cosa menos un concepto de programación es simplemente contraproducente. En lugar de odiarlos por la elección de palabras que ya no es la más apropiada, es hora de que aceptemos las cosas y sigamos adelante.
Aquí hay una cita de Larry Wall , el creador del propio Perl:
Y aquí hay una publicación de blog de uno de los desarrolladores principales de PHP :
Dicho esto, puede hacer coincidir palíndromos con expresiones regulares usando esto:
... que obviamente no tiene nada que ver con las gramáticas regulares.
Más información aquí: http://www.regular-expressions.info/balancing.html
fuente
Como algunos ya han dicho, no hay una expresión regular única que detecte un palíndromo general fuera de la caja, pero si desea detectar palíndromos hasta una cierta longitud, puede usar algo como
fuente
Ahora se puede hacer en Perl. Usando referencia recursiva:
modificado en base a la casi última parte http://perldoc.perl.org/perlretut.html
fuente
En ruby puede utilizar grupos de captura con nombre. entonces algo como esto funcionará -
Pruébalo, funciona ...
fuente
En realidad, es más fácil hacerlo con manipulación de cadenas en lugar de expresiones regulares:
Me doy cuenta de que esto realmente no responde a la pregunta de la entrevista, pero podría usarlo para mostrar cómo conoce una mejor manera de hacer una tarea, y no es la típica "persona con un martillo, que ve cada problema como un clavo". . "
fuente
Aquí está mi respuesta al quinto nivel de Regex Golf (Un hombre, un plan). Funciona para hasta 7 caracteres con Regexp del navegador (estoy usando Chrome 36.0.1985.143).
Aquí hay uno para hasta 9 caracteres.
Para aumentar el número máximo de caracteres para el que funcionaría, lo reemplazaría repetidamente . con (?: (.).? \ n?)? .
fuente
¡Las expresiones regulares recursivas pueden hacerlo!
Algoritmo tan simple y evidente para detectar una cadena que contiene un palíndromo:
En rexegg.com/regex-recursion, el tutorial explica cómo funciona.
Funciona bien con cualquier idioma, aquí un ejemplo adaptado de la misma fuente (enlace) como prueba de concepto, usando PHP:
salidas
Comparando
La expresión regular
^((\w)(?:(?1)|\w?)\2)$
hace el mismo trabajo, pero como sí / no "contiene".PD: está usando una definición en la que "o" no es un palimbromo, el formato con guiones "able-elba" no es un palíndromo, pero "ableelba" sí lo es. Nombrarlo definición 1 .
Cuando "o" y "able-elba" son palindrones, nombrar definition2 .
En comparación con otras "expresiones regulares palindrómicas",
^((.)(?:(?1)|.?)\2)$
la base-regex anterior sin\w
restricción, aceptando "capaz-elba".^((.)(?1)?\2|.)$
( @LilDevil ) Use definition2 (acepta "o" y "able-elba", por lo que también difieren en el reconocimiento de las cadenas "aaaaa" y "bbbb").^((.)(?1)\2|.?)$
( @Markus ) no se detectó "kook" ni "bbbb"^((.)(?1)*\2|.?)$
( @Csaba ) Utilice la definición 2 .NOTA: para comparar, puede agregar más palabras en
$subjects
y una línea para cada expresión regular comparada,fuente
También puede hacerlo sin utilizar la recursividad:
para permitir un solo carácter:
Funciona con Perl, PCRE
manifestación
Para Java:
manifestación
fuente
Con respecto a la expresión PCRE (de MizardX):
/^((.)(?1)\2|.?)$/
¿Lo has probado? En mi PHP 5.3 bajo Win XP Pro falla en: aaaba En realidad, modifiqué ligeramente la expresión de expresión para que se lea:
/^((.)(?1)*\2|.?)$/
Creo que lo que está sucediendo es que mientras el par de personajes externos están anclados, los internos restantes no lo están. Esta no es toda la respuesta porque si bien transmite incorrectamente "aaaba" y "aabaacaa", falla correctamente en "aabaaca".
Me pregunto si hay una corrección para esto y también, ¿el ejemplo de Perl (por JF Sebastian / Zsolt) pasa mis pruebas correctamente?
Csaba Gabor desde Viena
fuente
es válido para motor Oniguruma (que se usa en Ruby)
tomado de Pragmatic Bookshelf
fuente
En Perl (ver también la respuesta de Zsolt Botykai ):
fuente
Como señaló ZCHudson , determinar si algo es un palíndromo no se puede hacer con una expresión regular habitual, ya que el conjunto de palíndromos no es un lenguaje regular.
Estoy totalmente en desacuerdo con Airsource Ltd cuando dice que "no es posible" no es el tipo de respuesta que el entrevistador está buscando. Durante mi entrevista, llego a este tipo de preguntas cuando me enfrento a un buen candidato, para comprobar si puede encontrar el argumento correcto cuando le propusimos hacer algo mal. No quiero contratar a alguien que intente hacer algo de manera incorrecta si conoce mejor a alguien.
fuente
algo que puede hacer con perl: http://www.perlmonks.org/?node_id=577368
fuente
Le explicaría al entrevistador que el lenguaje que consiste en palíndromos no es un lenguaje regular sino que está libre de contexto.
La expresión regular que coincidiría con todos los palíndromos sería infinita . En cambio, le sugiero que se limite a aceptar un tamaño máximo de palíndromos; o si se necesitan todos los palíndromos, use como mínimo algún tipo de NDPA, o simplemente use la técnica simple de inversión de cadena / igual.
fuente
Lo mejor que puede hacer con las expresiones regulares, antes de quedarse sin grupos de captura:
Esto coincidirá con todos los palíndromos de hasta 19 caracteres de longitud.
La resolución programática para todas las longitudes es trivial:
fuente
Todavía no tengo el representante para comentar en línea, pero la expresión regular proporcionada por MizardX y modificada por Csaba se puede modificar aún más para que funcione en PCRE. La única falla que he encontrado es la cadena de un solo carácter, pero puedo probarla por separado.
/^((.)(?1)?\2|.)$/
Si puede hacer que falle en cualquier otra cadena, comente.
fuente
fuente
Desde la teoría de los autómatas es imposible igualar un paliandrome de cualquier longitud (porque eso requiere una cantidad infinita de memoria). Pero ES POSIBLE igualar Paliandromes de longitud fija. Digamos que es posible escribir una expresión regular que coincida con todos los paliandromes de longitud <= 5 o <= 6, etc., pero no> = 5, etc. donde el límite superior no está claro
fuente
En Ruby puede usar
\b(?'word'(?'letter'[a-z])\g'word'\k'letter+0'|[a-z])\b
para hacer coincidir palabras palíndromo comoa, dad, radar, racecar, and redivider
. ps: esta expresión regular solo coincide con las palabras palíndromo que tienen un número impar de letras.Veamos cómo esta expresión regular coincide con el radar. La palabra límite \ b coincide con el comienzo de la cadena. El motor de expresiones regulares ingresa al grupo de captura "palabra". [az] coincide con r que luego se almacena en la pila para el grupo de captura "letra" en el nivel de recursividad cero. Ahora el motor de expresiones regulares entra en la primera recursividad del grupo "palabra". (? 'letra' [az]) coincide y captura a en el nivel de recursividad uno. La expresión regular entra en la segunda recursión del grupo "palabra". (? 'letra' [az]) captura d en el nivel de recursividad dos. Durante las siguientes dos recursiones, el grupo captura a y r en los niveles tres y cuatro. La quinta recursión falla porque no quedan caracteres en la cadena para que [az] coincida. El motor de expresiones regulares debe retroceder.
El motor de expresiones regulares ahora debe probar la segunda alternativa dentro del grupo "palabra". La segunda [az] de la expresión regular coincide con la r final de la cadena. El motor ahora sale de una recursión exitosa, retrocediendo un nivel hasta la tercera recursión.
Después de hacer coincidir (& word) el motor llega a \ k'letter + 0 '. La referencia inversa falla porque el motor de expresiones regulares ya ha llegado al final de la cadena de asunto. Así que retrocede una vez más. La segunda alternativa ahora coincide con a. El motor de expresiones regulares sale de la tercera recursión.
El motor de expresiones regulares ha vuelto a coincidir (& word) y debe intentar la referencia inversa nuevamente. La referencia inversa especifica +0 o el nivel actual de recursividad, que es 2. En este nivel, el grupo de captura coincide con d. La referencia inversa falla porque el siguiente carácter de la cadena es r. Retrocediendo de nuevo, la segunda alternativa coincide d.
Ahora, \ k'letter + 0 'coincide con la segunda a en la cadena. Esto se debe a que el motor de expresiones regulares ha regresado a la primera recursión durante la cual el grupo de captura coincidió con la primera a. El motor de expresiones regulares sale de la primera recursión.
El motor de expresiones regulares ahora está fuera de toda recursividad. Que este nivel, el grupo de captura almacenó r. La referencia inversa ahora puede coincidir con la r final de la cadena. Dado que el motor ya no está dentro de ninguna recursividad, continúa con el resto de la expresión regular después del grupo. \ b coincide con el final de la cadena. Se alcanza el final de la expresión regular y el radar se devuelve como coincidencia general.
fuente
aquí está el código PL / SQL que dice si la cadena dada es palíndromo o no usando expresiones regulares:
fuente
fuente
Esta expresión regular detectará palíndromos de hasta 22 caracteres ignorando espacios, tabulaciones, comas y comillas.
Juega con él aquí: https://regexr.com/4tmui
fuente
Un ligero refinamiento del método de Airsource Ltd, en pseudocódigo:
fuente