Para el propósito de este desafío, decimos que un patrón regex coincide con una cadena si todo cadena coincide con el patrón, no solo una subcadena.
Dados dos patrones de expresiones regulares A y B , decimos que A es más especializado que B si cada cadena que A coincide también coincide con B pero no al revés. Decimos que A es equivalente a B si ambos patrones coinciden exactamente con el mismo conjunto de cadenas. Si ninguno de los patrones es más especializado que el otro ni son equivalentes, decimos que A y B son incomparables .
Por ejemplo, el patrón Hello, .*!
es más especializado que .*, .*!
; los patrones (Hello|Goodbye), World!
y Hello, World!|Goodbye, World!
son equivalentes; y los patrones Hello, .*!
y.*, World!
son incomparables.
La relación "más especializado que" define un orden parcial estricto en el conjunto de patrones de expresiones regulares. En particular, para todos los patrones A y B , se cumple exactamente uno de los siguientes:
- A es más especializado que B ( A < B ).
- B es más especializado que A ( A > B ).
- A y B son equivalentes ( A = B ).
- A y B son incomparables ( A ∥ B ).
Cuando A y B son incomparables, podemos distinguir aún más entre dos casos:
- A y B son disjuntos ( A ∥ B ), lo que significa que ninguna cadena coincide con ambos.
- A y B se cruzan ( A ≬ B ), lo que significa que algunas cadenas coinciden con ambas.
Reto
Escriba un programa o una función que tome un par de patrones de expresiones regulares y los compare usando el orden anterior. Es decir, si los dos patrones son A y B , el programa debe determinar si A < B , A > B ,
A = B o A ∥ B .
× 92% de bonificación Se otorga una bonificación adicional si, cuando los patrones son incomparables, el programa determina si se cruzan o no.
Entrada y salida
El programa debe aceptar dos patrones de expresiones regulares, como cadenas, en el sabor definido a continuación. Puede leer la entrada a través de STDIN , la línea de comando , como argumentos de función o un método equivalente . Puede suponer que los patrones son válidos.
El programa debe producir una de exactamente cuatro salidas distintas (o cinco salidas distintas si va a obtener la bonificación anterior), dependiendo del resultado de la comparación (las salidas exactas dependen de usted). Puede escribir la salida en STDOUT , devuélvalo como resultado de la función o use un método equivalente .
Sabor Regex
Puede admitir las funciones de expresión regular que desee, pero debe admitir las siguientes:
- Alternancia con
|
. - Cuantificación con
*
. - Agrupando con
(
y)
. - Emparejar cualquier personaje (posiblemente excluyendo nuevas líneas) con
.
. - (Opcional: × 80% de bonificación) Relacionar clases de caracteres simples y negadas con
[…]
y[^…]
, respectivamente. No tiene que admitir ninguna clase de caracteres predefinida (por ejemplo[:digit:]
), pero debe admitir rangos de caracteres. - Personaje escapando con
\
. Al menos debería ser posible eliminar caracteres especiales (es decir|*().[^-]\
) y preferiblemente también caracteres especiales comunes en otros sabores (por ejemplo{}
), pero el comportamiento al escapar de caracteres no especiales no está especificado. En particular, no tiene que admitir secuencias de escape especiales, como\n
una nueva línea y similares. Una posible implementación es simplemente tomar el carácter que sigue al\
literal.
Puede suponer la existencia de un carácter de entrada que no puede ser igualado por ningún literal (es decir, solo puede ser igualado por .
clases de caracteres negadas).
Reglas Adicionales
- Puede usar las bibliotecas de expresiones regulares o la funcionalidad de expresiones regulares incorporadas solo con el propósito de la coincidencia y reemplazo de cadenas.
- Puede ignorar cualquier problema relacionado con la configuración regional, como las reglas de intercalación.
- Para decir lo obvio: su programa debe finalizar. Debe ejecutarse en un tiempo razonable dados los patrones típicos (definitivamente no más de una hora, preferiblemente mucho menos).
Tanteo
Este es el código de golf. Su puntaje es el producto del tamaño del código , en bytes, y cualquiera de los bonos . El puntaje más bajo gana.
Casos de prueba
El formato de los casos de prueba es el siguiente:
<Test ID>
<Pattern A>
<Ordering>
<Pattern B>
<Test ID>
<Pattern A>
<Ordering>
<Pattern B>
...
Donde <Test ID>
es un identificador para el caso de prueba, <Pattern A>
y <Pattern B>
son los patrones de expresiones regulares y <Ordering>
el orden entre ellos, y es uno de:
<
:<Pattern A>
es más especializado que<Pattern B>
.>
:<Pattern B>
es más especializado que<Pattern A>
.=
: Los patrones son equivalentes.|
: Los patrones son incomparables y disjuntos.X
: Los patrones son incomparables e intersectantes.
El valor especial <empty pattern>
representa el patrón vacío.
A. Patrones básicos
B. Patrones complejos
C. Patrones básicos con clases de caracteres.
D. Patrones complejos con clases de caracteres.
Programa de prueba
El siguiente fragmento se puede utilizar para comparar patrones de expresiones regulares:
<style>#main {display: none;}#main[loaded] {display: inline;}.pattern_container {position: relative;}.pattern_underlay, .pattern {font: 12pt courier, monospace;overflow: hidden;white-space: pre;padding: 7px;box-sizing: border-box;}.pattern_underlay {background-color: #dddddd;color: #707070;border-radius: 4px;box-shadow: 0.5px 0.5px 2.5px #aaaaaa;}.pattern_underlay[error] {background-color: #ffccbb;}.pattern {position: absolute;left: 0px;top: 0px;background: none;border: none;width: 100%;height: 100%;resize: none;white-space: normal;}#ordering {min-width: 28pt;text-align: center;font-size: 16pt;}#status {padding: 5px;background-color: #fffdce;box-shadow: 1.5px 1.5px 3.5px #aaaaaa;font-size: 10pt;white-space: pre;display: none;}#status[error] {display: inline;background-color: #ffe8df;}#status[loading] {display: inline;}.inline_code {background-color: #dddddd;font: 12pt courier, monospace;padding: 2px;}.placeholder {visibility: hidden;}.error_text {background-color: #fffcb7};</style><span id="main"><table><tr><td><div class="pattern_container"><div class="pattern_underlay" id="pattern1_underlay"></div><textarea class="pattern" id="pattern1" oninput="compare()">Hello, .*!</textarea></div></td><td id="ordering"></td><td><div class="pattern_container"><div class="pattern_underlay" id="pattern2_underlay"></div><textarea class="pattern" id="pattern2" oninput="compare()">.*, .*!</textarea></div></td></tr></table><br></span><span id="status" loading>Loading...</span><script type='text/javascript'>var Module = {setStatus: function (status) {document.getElementById("status").innerHTML = status;if (status == "") {compare();document.getElementById("status").removeAttribute("loading");document.getElementById("main").setAttribute("loaded", 1);}}};function underlay_chars(str) {if (/^\n*$/.exec(str))return str.split("\n").map(function () { return '<span class="placeholder"> \n</span>'; });if (str.indexOf("\n") >= 0)str = str.replace(/\s*$/gm, function (m) { return m.replace(/[^\n]/g, "\0"); });return (str + "\n").split("").map(function (c) {if (c == "\0") return "·";else return '<span class="placeholder">' + c + '</span>';});}function underlay_str(str) {return underlay_chars(str).join("");}function str_to_array32(str) {a = [];for (c of str) {n = c.charCodeAt(0);a.push(n & 0xff, (n >> 8) & 0xff, (n >> 16) & 0xff, n >> 24);}a.push(0, 0, 0, 0);return a;}function compare() {try {for (e of ["pattern1_underlay", "pattern2_underlay", "status"])document.getElementById(e).removeAttribute("error");for (e of ["pattern1", "pattern2"])document.getElementById(e + "_underlay").innerHTML = underlay_str(document.getElementById(e).value);c = Module.ccall("regex_compare", "number", ["array", "array"], [str_to_array32(document.getElementById("pattern1").value),str_to_array32(document.getElementById("pattern2").value)]);if (c >= 0)document.getElementById("ordering").innerHTML = "∥≬<>="[c];else {i = Module.ccall("regex_error_index", "number", [], []);l = Module.ccall("regex_error_length", "number", [], []);e = document.getElementById("pattern" + -c + "_underlay");t = underlay_chars(document.getElementById("pattern" + -c).value);e.setAttribute("error", 1);e.innerHTML =t.slice(0, i).join("") +'<span class="error_text">' + t.slice(i, i + l).join("") + "</span>" +t.slice(i + l).join("");e.setAttribute("error", 1);throw "Pattern error: " + Module.ccall("regex_error", "string", [], []).replace(/`(.*?)'/g, '<span class="inline_code">$1</span>');}} catch (e) {document.getElementById("ordering").innerHTML = "??";document.getElementById("status").innerHTML = e;document.getElementById("status").setAttribute("error", 1);}}</script><script async type="text/javascript" src="https://gist.githack.com/anonymous/91f27d6746566c7b4e4c/raw/c563bf84a01c3a1c6e5f021369a3e730a2e74a1a/rpo.js"></script>
Respuestas:
Python 2, 522 bytes * .92 = 480.24
537.28Edición 2 : -60 bytes
Editar : explicación añadida.
Definida es la función
f
que toma las dos cadenas de patrones como argumentos y devuelve'<'
,'='
,'>'
,'|'
, o'X'
. Se necesita menos de un minuto para procesar todos los casos de prueba.El código consiste en lo siguiente, pero con
\r
,\n
\t
y los escapes hexadecimales (pero no\0
) reemplazados con sus valores de bytes reales.La declaración anterior hace que se ejecute el siguiente código:
Si la segunda muestra de código se almacena en la cadena
s
, la expresión puede producir algo similar a la primera'#encoding=Latin\nexec"""%s"""'%__import__('zlib').compress(s)
. Puede ser necesario corregir algunos caracteres, como bytes nulos o barras diagonales inversas. El código descomprimido es de casi1000800 bytes, por lo que quizás esté más ofuscado que el golf ... pero al menos logré jugar un poco la codificación: deLatin1
aLatin
.Explicación
El programa funciona mediante el uso de los índices de la cadena como una forma cruda de realizar un seguimiento de los estados de análisis de una cadena. La
n
función construye tablas de transición. Primero analiza la cadena y encuentra todas las instancias de dos tipos de transiciones. Primero, hay transiciones que no implican agregar otra letra a la cadena. Por ejemplo, saltar de*
a al principio de una expresión cuantificada. En segundo lugar, hay transiciones de agregar un carácter, que simplemente avanzan un índice. Luego se calcula el cierre transitivo de las transiciones sin caracteres, y esos son sustituidos por los destinos de las transiciones de 1 carácter. Por lo tanto, devuelve una asignación de un índice y un carácter a un conjunto de índices.La función principal realiza un BFS sobre posibles cadenas de entrada. Realiza un seguimiento de un conjunto de todos los índices posibles para cualquier fragmento de una cadena que esté considerando. Lo que nos interesa encontrar es estados que sean aceptados por ambas expresiones regulares, o por una y no por la otra. Para mostrar que se acepta una expresión regular, solo es necesario encontrar un posible camino de transiciones al final del patrón. Pero para mostrar que uno es rechazado, es necesario haber analizado todos los caminos posibles. Por lo tanto, para determinar si los conjuntos de estados posibles para el patrón A y el patrón B ya están cubiertos por los que se han analizado anteriormente, se registran los pares de un solo estado en una expresión regular y el conjunto de todos los estados posibles en el otro. Si no hay nuevos, entonces está bien volver. Por supuesto, también sería posible, y menos personajes,
fuente
x 0.92
bono cuando calcule su puntaje. Y, por supuesto, ¡una explicación es bienvenida!Haskell,
560553618podría obtener algunos de los bonos en el futuro.
esto aún no está totalmente golfizado.
Una explicación manual del algoritmo:
reg!reg'
devuelve el carácter requerido, uno de "= <> x".a#b
es cierto si no todas las cadenas quea
coinciden también coinciden conb
.c%reg
es una lista de expresiones regulares quereg
coincidec:s
si una de las expresiones regulares en la salida coincides
. Básicamente coincide parcialmente con la expresión regular. excepto sic
es así'\0'
. entonces obligareg
a no recibir más información, regresando[]
sireg
debe obtener más información para que coincida y[""]
contrario.#
funciona generando una lista finita de todos los posibles "estados de expresión regular" en los que estarán las dos expresiones regulares después de una cadena arbitraria. luego, para verificar sia<b
verificamos el clima, hay un "estado regex" en el quea
se coincide por completo perob
no se coincide por completo.fuente
B4
.