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>
Réponses:
Python 2, 522 octets * .92 = 480,24
537,28Édition 2 : -60 octets
Edit : Ajout d'une explication.
Défini est la fonction
f
qui prend les deux chaînes de modèle comme arguments et les rendements'<'
,'='
,'>'
,'|'
, ou'X'
. Moins d'une minute est nécessaire pour traiter tous les cas de test.Le code se compose des éléments suivants, mais avec
\r
,\n
\t
et les échappements hexadécimaux (mais pas\0
) remplacés par leurs valeurs d'octets réelles.L'instruction ci-dessus provoque l'exécution du code suivant:
Si le deuxième exemple de code est stocké dans la chaîne
s
, quelque chose de similaire au premier peut être produit par l'expression'#encoding=Latin\nexec"""%s"""'%__import__('zlib').compress(s)
. Il peut être nécessaire de corriger certains caractères tels que les octets nuls ou les barres obliques inverses. Le code décompressé fait près de1000800 octets, donc il est peut-être plus obscur que le golf ... mais au moins j'ai réussi à jouer un peu à l'encodage: deLatin1
àLatin
.Explication
Le programme fonctionne en utilisant les indices de la chaîne comme un moyen grossier de garder une trace des états d'analyse d'une chaîne. La
n
fonction crée des tables de transition. Tout d'abord, il analyse la chaîne et trouve toutes les instances de deux types de transitions. Tout d'abord, il existe des transitions qui n'impliquent pas l'ajout d'une autre lettre à la chaîne. Par exemple, passer de a*
au début d'une expression quantifiée. Deuxièmement, il y a des transitions d'ajout d'un caractère, qui avancent simplement d'un index. Ensuite, la fermeture transitive des transitions sans caractère est calculée, et celles-ci sont substituées aux destinations des transitions à 1 caractère. Il renvoie donc un mappage d'un index et d'un caractère à un ensemble d'indices.La fonction principale effectue un BFS sur les chaînes d'entrée possibles. Il suit un ensemble de tous les indices possibles pour n'importe quel fragment d'une chaîne qu'il envisage. Ce que nous voulons trouver, ce sont des états qui sont acceptés soit par les deux expressions rationnelles, soit par l'un et pas l'autre. Pour montrer qu'une expression régulière est acceptée, il suffit de trouver un chemin possible de transitions jusqu'à la fin du motif. Mais pour montrer que l'on est rejeté, il faut avoir analysé tous les chemins possibles. Par conséquent, pour déterminer si les ensembles d'états possibles pour le motif A et le motif B sont déjà couverts par ceux qui ont été analysés auparavant, des paires d'un seul état dans une expression régulière et l'ensemble de tous les états possibles dans l'autre sont enregistrés. S'il n'y en a pas de nouveau, c'est OK pour revenir en arrière. Bien sûr, il serait également possible, et moins de caractères,
la source
x 0.92
bonus lorsque vous calculez votre score. Et, bien sûr, une explication est la bienvenue!Haskell,
560553618pourrait obtenir certains des bonus à l'avenir.
ce n'est pas encore entièrement joué.
une explication ondulée à la main de l'algorithme:
reg!reg'
renvoie le caractère requis, l'un de "= <> x".a#b
est vrai si toutes les chaînes quia
correspondent ne le sont pasb
.c%reg
est une liste d'expressions régulières telles qu'ellesreg
correspondent à l'c:s
une des expressions rationnelles des correspondances de sorties
. i correspond fondamentalement partiellement à l'expression régulière. sauf sic
c'est le cas'\0'
. alors il forcereg
à ne plus obtenir d'entrée, retournant[]
sireg
doit obtenir plus d'entrée à faire correspondre et[""]
autrement.#
fonctionne en générant une liste finie de tous les "états de regex" possibles dans lesquels les deux regexps se trouveront après une chaîne arbitraire. puis pour vérifier sia<b
nous vérifions la météo, il y a un "état regex" dans lequel ila
est entièrement mis en correspondance maisb
ne l'est pas complètement.la source
B4
.