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>