Ai fini di questa sfida, diciamo che un modello regex corrisponde a una stringa se l' intera stringa è associata al modello, non solo a una sottostringa.
Dati due motivi regex A e B , diciamo che A è più specializzato di B se ogni stringa che è abbinata a A è eguagliata anche da B ma non viceversa. Diciamo che A è equivalente a B se entrambi i modelli corrispondono esattamente allo stesso insieme di stringhe. Se nessuno dei due pattern è più specializzato dell'altro né sono equivalenti, diciamo che A e B sono incomparabili .
Ad esempio, il modello Hello, .*!
è più specializzato di .*, .*!
; i modelli (Hello|Goodbye), World!
e Hello, World!|Goodbye, World!
sono equivalenti; e i modelli Hello, .*!
e.*, World!
sono incomparabili.
La relazione "più specializzato di" definisce un rigoroso ordine parziale sull'insieme di schemi regex. In particolare, per tutti i modelli A e B , è vera una delle seguenti condizioni:
- A è più specializzato di B ( A < B ).
- B è più specializzato di A ( A > B ).
- A e B sono equivalenti ( A = B ).
- A e B sono incomparabili ( A ∥ B ).
Quando A e B sono incomparabili, possiamo ulteriormente distinguere tra due casi:
- A e B sono disgiunti ( A ∥ B ), il che significa che nessuna stringa è abbinata da entrambi.
- A e B si intersecano ( A ≬ B ), il che significa che alcune stringhe sono abbinate da entrambi.
Sfida
Scrivi un programma o una funzione che accetta una coppia di schemi regex e li confronta usando l'ordine sopra. Cioè, se i due modelli sono A e B , il programma dovrebbe determinare se A < B , A > B ,
A = B o A ∥ B .
× Bonus del 92% Viene dato un bonus aggiuntivo se, quando gli schemi sono incomparabili, il programma determina se si intersecano o si disgiungono.
Ingresso e uscita
Il programma dovrebbe accettare due pattern regex, come stringhe, con il sapore definito di seguito. È possibile leggere l'input tramite STDIN , la riga di comando , come argomenti di funzione o un metodo equivalente . Si può presumere che i modelli siano validi.
Il programma dovrebbe produrre esattamente uno dei quattro output distinti (o cinque output distinti se stai per ottenere il bonus sopra), a seconda del risultato del confronto (gli output esatti dipendono da te.) Puoi scrivere l'output su STDOUT , restituiscilo come risultato della funzione o usa un metodo equivalente .
Sapore di Regex
Puoi supportare qualunque funzionalità regex ti piaccia, ma devi supportare le seguenti:
- Alternanza con
|
. - Quantificazione con
*
. - Raggruppamento con
(
e)
. - Abbinare qualsiasi personaggio (possibilmente escludendo le nuove linee) con
.
. - (Opzionale: × 80% di bonus) Abbinamento di classi di personaggi semplici e negate con
[…]
e[^…]
, rispettivamente. Non è necessario supportare classi di caratteri predefinite (ad es.[:digit:]
) Ma è necessario supportare intervalli di caratteri. - Personaggio in fuga con
\
. Dovrebbe almeno essere possibile escludere caratteri speciali (ad es.|*().[^-]\
) E preferibilmente anche caratteri speciali comuni in altri gusti (ad es.{}
), Ma il comportamento durante la fuga di caratteri non speciali non è specificato. In particolare, non è necessario supportare sequenze di escape speciali come\n
per una nuova riga e simili. Una possibile implementazione è semplicemente quella di prendere il personaggio\
come letterale.
Si può presumere l'esistenza di un carattere di input che non può essere confrontato da nessun letterale (cioè può solo essere abbinato a .
classi di caratteri negate).
Regole aggiuntive
- È possibile utilizzare le librerie regex o la funzionalità regex incorporata solo ai fini della corrispondenza e della sostituzione delle stringhe.
- È possibile ignorare qualsiasi problema relativo alle impostazioni locali, come le regole di confronto.
- Per affermare l'ovvio: il programma deve terminare. Dovrebbe essere eseguito in un ragionevole lasso di tempo, dati i modelli tipici (sicuramente non più di un'ora, preferibilmente molto meno).
punteggio
Questo è code-golf. Il tuo punteggio è il prodotto della dimensione del codice , in byte e uno qualsiasi dei bonus . Le punteggio più basso vince.
Casi test
Il formato dei casi di test è il seguente:
<Test ID>
<Pattern A>
<Ordering>
<Pattern B>
<Test ID>
<Pattern A>
<Ordering>
<Pattern B>
...
Dove si <Test ID>
trova un identificatore per il caso di test, <Pattern A>
e <Pattern B>
sono i modelli regex ed <Ordering>
è l'ordinamento tra di loro, ed è uno di:
<
:<Pattern A>
è più specializzato di<Pattern B>
.>
:<Pattern B>
è più specializzato di<Pattern A>
.=
: I modelli sono equivalenti.|
: I modelli sono incomparabili e disgiunti.X
: I motivi sono incomparabili e intersecanti.
Il valore speciale <empty pattern>
sta per il modello vuoto.
A. Schemi di base
B. Modelli complessi
C. Schemi di base con classi di caratteri
D. Schemi complessi con classi di caratteri
Programma di test
Il seguente frammento può essere utilizzato per confrontare i pattern regex:
<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>