Aux fins de ce défi, nous disons qu'un modèle d'expression régulière correspond à une chaîne si la chaîne entière correspond au modèle, et pas seulement à une sous-chaîne.
Étant donné deux modèles d'expression régulière A et B , nous disons que A est plus spécialisé que B si chaque chaîne qui est mise en correspondance par A est également mise en correspondance par B, mais pas l'inverse. Nous disons que A est équivalent à B si les deux modèles correspondent exactement au même ensemble de chaînes. Si aucun motif n'est plus spécialisé que l'autre et qu'ils ne sont pas équivalents, nous disons que A et B sont incomparables .
Par exemple, le modèle Hello, .*!
est plus spécialisé que .*, .*!
; les motifs (Hello|Goodbye), World!
et Hello, World!|Goodbye, World!
sont équivalents; et les motifs Hello, .*!
et .*, World!
sont incomparables.
La relation "plus spécialisée que" définit un ordre partiel strict sur l'ensemble des motifs d'expression régulière. En particulier, pour tous les modèles A et B , exactement l'une des conditions suivantes est vraie:
- A est plus spécialisé que B ( A < B ).
- B est plus spécialisé que A ( A > B ).
- A et B sont équivalents ( A = B ).
- A et B sont incomparables ( A ∥ B ).
Lorsque A et B sont incomparables, on peut encore distinguer deux cas:
- A et B sont disjoints ( A ∥ B ), ce qui signifie qu'aucune chaîne n'est mise en correspondance par les deux.
- A et B se croisent ( A ≬ B ), ce qui signifie que certaines chaînes sont appariées par les deux.
Défi
Écrivez un programme ou une fonction qui prend une paire de motifs d'expression régulière et les compare en utilisant l'ordre ci-dessus. Autrement dit, si les deux modèles sont A et B , le programme devrait déterminer si A < B , A > B ,
A = B ou A ∥ B .
× 92% Bonus Un bonus supplémentaire est accordé si, lorsque les motifs sont incomparables, le programme détermine s'ils sont entrecroisés ou disjoints.
Entrée et sortie
Le programme doit accepter deux modèles d'expression régulière, sous forme de chaînes, dans la saveur définie ci-dessous. Vous pouvez lire l'entrée via STDIN , la ligne de commande , comme arguments de fonction ou une méthode équivalente . Vous pouvez supposer que les modèles sont valides.
Le programme devrait produire l'une des quatre sorties distinctes (ou cinq sorties distinctes si vous optez pour le bonus ci-dessus), selon le résultat de la comparaison (les sorties exactes dépendent de vous.) Vous pouvez écrire la sortie dans STDOUT , renvoyez-la comme résultat de la fonction ou utilisez une méthode équivalente .
Arôme Regex
Vous pouvez prendre en charge les fonctionnalités regex que vous aimez, mais vous devez prendre en charge les suivantes:
- Alternance avec
|
. - Quantification avec
*
. - Regroupement avec
(
et)
. - Faire correspondre n'importe quel caractère (éventuellement à l'exclusion des sauts de ligne) avec
.
. - (Facultatif: × 80% de bonus) Faire correspondre les classes de personnages simples et inversées avec
[…]
et[^…]
, respectivement. Vous n'avez pas à prendre en charge de classes de caractères prédéfinies (par exemple[:digit:]
), mais vous devez prendre en charge les plages de caractères. - Caractère s'échappant avec
\
. Il devrait au moins être possible d'esacpe des caractères spéciaux (ie|*().[^-]\
) et de préférence également des caractères spéciaux communs dans d'autres versions (par exemple{}
), mais le comportement lors de l'échappement de caractères non spéciaux n'est pas spécifié. En particulier, vous n'avez pas à prendre en charge des séquences d'échappement spéciales telles que\n
pour une nouvelle ligne, etc. Une implémentation possible consiste simplement à prendre le caractère suivant le\
comme un littéral.
Vous pouvez supposer l'existence d'un caractère d'entrée qui ne peut être mis en correspondance par aucun littéral (c'est-à-dire qu'il ne peut être mis en correspondance que par des .
classes de caractères niées).
Règles supplémentaires
- Vous pouvez utiliser des bibliothèques regex ou des fonctionnalités regex intégrées uniquement à des fins de correspondance et de remplacement de chaînes.
- Vous pouvez ignorer tous les problèmes liés aux paramètres régionaux, tels que les règles de classement.
- Pour dire l'évidence: votre programme doit se terminer. Il devrait s'exécuter dans un délai raisonnable compte tenu des modèles typiques (certainement pas plus d'une heure, de préférence beaucoup moins).
Notation
C'est du code-golf. Votre score est le produit de la taille du code , en octets, et de l'un des bonus . Le score le plus bas l' emporte.
Cas de test
Le format des cas de test est le suivant:
<Test ID>
<Pattern A>
<Ordering>
<Pattern B>
<Test ID>
<Pattern A>
<Ordering>
<Pattern B>
...
Où <Test ID>
est un identifiant pour le cas de test, <Pattern A>
et <Pattern B>
sont les modèles d'expression régulière et <Ordering>
est l'ordre entre eux, et est l'un des:
<
:<Pattern A>
est plus spécialisé que<Pattern B>
.>
:<Pattern B>
est plus spécialisé que<Pattern A>
.=
: Les motifs sont équivalents.|
: Les motifs sont incomparables et disjoints.X
: Les motifs sont incomparables et entrecroisés.
La valeur spéciale <empty pattern>
représente le motif vide.
A. Modèles de base
Modèles complexes
C. Modèles de base avec classes de caractères
D. Modèles complexes avec classes de caractères
Programme de test
L'extrait de code suivant peut être utilisé pour comparer des modèles d'expression régulière:
<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>