Für diesen Zweck wird gesagt, dass ein reguläres Muster mit einer Zeichenfolge übereinstimmt, wenn die gesamte Zeichenfolge mit dem Muster übereinstimmt, nicht nur mit einer Teilzeichenfolge.
Gegeben seien zwei regex Muster A und B , sagen wir , dass A ist mehr spezialisiert als B , wenn jede Zeichenfolge, die durch abgestimmte A auch durch abgestimmte B , aber nicht umgekehrt. Wir sagen , dass A ist äquivalent zu B , wenn beide Muster entsprechen genau den gleichen Satz von Saiten. Wenn weder Muster mehr als die andere spezialisiert , noch sind sie gleichwertig, sagen wir , dass A und B sind unvergleichlich .
Zum Beispiel ist das Muster Hello, .*!
spezialisierter als .*, .*!
; die Muster (Hello|Goodbye), World!
und Hello, World!|Goodbye, World!
sind gleichwertig; und die Muster Hello, .*!
und .*, World!
sind unvergleichlich.
Die Beziehung "spezialisierter als" definiert eine strikte Teilreihenfolge auf der Menge der Regex-Muster. Insbesondere gilt für alle Muster A und B genau eines der folgenden:
- A ist spezialisierter als B ( A < B ).
- B ist spezialisierter als A ( A > B ).
- A und B sind äquivalent ( A = B ).
- A und B sind unvergleichlich ( A ∥ B ).
Wenn A und B nicht vergleichbar sind, können wir weiter zwischen zwei Fällen unterscheiden:
- A und B sind disjunkt ( A ∥ B ), was bedeutet, dass beide Zeichenfolgen nicht übereinstimmen.
- A und B sind sich schneidende ( A ≬ B ), was bedeutet , dass einige Zeichenketten durch beide aufeinander abgestimmt sind.
Herausforderung
Schreiben Sie ein Programm oder eine Funktion , die ein Paar von Regex-Mustern verwendet und diese in der oben angegebenen Reihenfolge vergleicht. Das heißt, wenn die beiden Muster A und B sind , sollte das Programm bestimmen, ob A < B , A > B ,
A = B oder A ∥ B ist .
× 92% Bonus Ein zusätzlicher Bonus wird gewährt, wenn das Programm bei unvergleichlichen Mustern feststellt, ob sie sich überschneiden oder nicht.
Ein- und Ausgang
Das Programm sollte zwei Regex-Muster als Zeichenfolgen in der unten definierten Variante akzeptieren. Sie können die Eingabe über STDIN , die Befehlszeile , als Funktionsargumente oder eine äquivalente Methode lesen . Sie können davon ausgehen, dass die Muster gültig sind.
Das Programm sollte abhängig vom Ergebnis des Vergleichs eine von genau vier verschiedenen Ausgaben erzeugen (oder fünf verschiedene Ausgaben, wenn Sie den obigen Bonus anstreben ) (die genauen Ausgaben liegen bei Ihnen.) Sie können die Ausgabe an STDOUT schreiben , geben Sie es als Ergebnis der Funktion zurück oder verwenden Sie eine äquivalente Methode .
Regex Aroma
Sie können beliebige reguläre Ausdrücke unterstützen, müssen jedoch die folgenden unterstützen:
- Wechsel mit
|
. - Quantifizierung mit
*
. - Gruppieren mit
(
und)
. - Passende jedes Zeichen (möglicherweise mit Ausnahme von Zeilenumbrüchen) mit
.
. - (Optional: × 80% Bonus) Kombinieren Sie einfache und negierte Charakterklassen mit
[…]
und[^…]
. Sie müssen keine vordefinierten Zeichenklassen unterstützen (z. B.[:digit:]
), aber Sie sollten Zeichenbereiche unterstützen. - Charakter Flucht mit
\
. Es sollte zumindest möglich sein, Sonderzeichen (dh|*().[^-]\
) und vorzugsweise auch übliche Sonderzeichen in anderen Geschmacksrichtungen (zB{}
) zu maskieren , aber das Verhalten beim Maskieren von Nicht-Sonderzeichen ist nicht spezifiziert. Insbesondere müssen Sie keine speziellen Escape-Sequenzen wie\n
Newline und dergleichen unterstützen. Eine mögliche Implementierung besteht einfach darin, das Zeichen, das dem folgt,\
als Literal zu verwenden.
Sie können davon ausgehen, dass es ein Eingabezeichen gibt, das von keinem Literal abgeglichen werden kann (dh, es kann nur von .
und mit negierten Zeichenklassen abgeglichen werden ).
Zusätzliche Regeln
- Sie dürfen Regex-Bibliotheken oder integrierte Regex-Funktionen nur zum Zwecke des Abgleichs und Ersetzens von Zeichenfolgen verwenden.
- Sie können alle Probleme im Zusammenhang mit dem Gebietsschema ignorieren, z. B. Sortierregeln.
- Um das Offensichtliche zu sagen: Ihr Programm muss beendet werden. Es sollte in angemessener Zeit ausgeführt werden, wenn typische Muster vorliegen (definitiv nicht mehr als eine Stunde, vorzugsweise viel weniger).
Wertung
Das ist Code-Golf. Ihr Ergebnis ist das Produkt der Codegröße in Byte und eine der Prämien . Die niedrigste Punktzahl gewinnt.
Testfälle
Das Format der Testfälle ist wie folgt:
<Test ID>
<Pattern A>
<Ordering>
<Pattern B>
<Test ID>
<Pattern A>
<Ordering>
<Pattern B>
...
Wo <Test ID>
ist ein Bezeichner für den Testfall <Pattern A>
und <Pattern B>
sind die Regex-Muster und <Ordering>
ist die Reihenfolge zwischen ihnen und ist eine der folgenden:
<
:<Pattern A>
ist spezialisierter als<Pattern B>
.>
:<Pattern B>
ist spezialisierter als<Pattern A>
.=
: Die Muster sind gleichwertig.|
: Die Muster sind unvergleichlich und unzusammenhängend.X
: Die Muster sind unvergleichlich und überschneiden sich.
Der spezielle Wert <empty pattern>
steht für das leere Muster.
A. Grundmuster
B. Komplexe Muster
C. Grundmuster mit Zeichenklassen
D. Komplexe Muster mit Zeichenklassen
Testprogramm
Das folgende Snippet kann zum Vergleichen von Regex-Mustern verwendet werden:
<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>