Invertire una regex


27

La sfida

Dato un regex valido, genera un regex che corrisponde allo stesso set di stringhe, ma invertito.

L'obiettivo

Questa sfida utilizza il maggior numero di operazioni di base regex: ^, $, ?, +, *, [], {}, |. Non esistono gruppi di acquisizione o cose così complicate. È possibile sfuggire a caratteri speciali.

Ingresso / uscita campione

Nota: non verrà mai fornito un input non valido e in genere ci sono più risposte possibili per un determinato input!

Input      | Sample Output
-----------|-------------
abc        | cba
tuv?       | v?ut
a(b|c)     | (c|b)a
1[23]      | [23]1
a([bc]|cd) | (dc|[bc])a
^a[^bc]d$  | ^d[^bc]a$
x[yz]{1,2} | [yz]{1,2}x
p{2}       | p{2}
q{7,}      | q{7,}
\[c[de]    | [de]c\[
ab[c       | <output undefined>
a(?bc)     | <output undefined>
a[]]bc     | <output undefined>

dimostrazione

Demo funzionante che dimostra input / output corretti. Questo ha una logica aggiuntiva per la convalida degli input che non è necessaria in una risposta reale. Considera input non validi come comportamento indefinito.

specifiche

Per semplicità, tutti i caratteri speciali hanno il loro significato speciale o sono sfuggiti; cioè, [[]non è un intervallo di caratteri per [. Gli intervalli di lunghezza provengono dalle ERE POSIX standard; cioè {n}, {n,}e {n,m}sono supportati. I caratteri variano []e [^]sono supportati. A causa di queste regole e poiché non viene fornito alcun input non valido, è necessario solo copiarne il contenuto direttamente nell'output. Infine, l'avidità non ha importanza, cioè non importa se il regex invertito trova prima una corrispondenza diversa , deve solo trovare una corrispondenza per lo stesso set di stringhe.

punteggio

Vince il programma più piccolo in byte (escluso cheat come richieste di rete). Il programma può utilizzare l'IO reale o semplicemente definire una funzione.


1
Perché non c'è niente ?a cui attaccarsi. Prova a digitare /a(?bc)/nella console del browser.
TND,

3
Sembra buono ora. (^a|b)(c$|d)Tuttavia, potresti voler aggiungere qualcosa come un caso di prova.
Martin Ender,

Possiamo supporre che l'input conterrà solo caratteri ASCII stampabili? In particolare, nessun carattere di avanzamento riga?
Martin Ender,

1
Dovremmo considerare i qualificatori applicati ai gruppi, ad esempio (a)?(b)+(b)+(a)??
kennytm,

1
Manca il tuo elenco di operazioni regex (), utilizzato nel tuo esempio.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Risposte:


7

Retina , 136 114 110 byte

Yo dawg, ti ho sentito come regex ...

^
;
(T`^$`$^`;.
(.*);(\[(\\.|[^]])*]|\\.|.)([*+?]|{\d+(,|,\d+)?})?
$2$4!$1;
^\(!
) 
^\)(.*)!(.+?) 
($2$1
;$|!
<empty>

Dove <empty>rappresenta una riga finale vuota. Esegui il codice da un singolo file con il -sflag.

... quando vuoi invertire regex dovresti usare regex. Quando vuoi usare regex dovresti usare un linguaggio di programmazione basato su regex.

Questo codice presuppone che l'input non contenga né ;!né spazi. Anche se concordo sul fatto che si tratta di un presupposto piuttosto forte e potenzialmente non valido, è possibile sostituire quei tre nel codice con tre caratteri non stampabili (come byte null, carattere di campana, lo <DEL>si chiama) e non influirebbe sulla dimensione o sulla funzionalità del codice affatto.

Aggiungerò una spiegazione quando avrò finito di giocare a golf.


3
"I herd * you liek *"
lirtosiast

Penso che il codice presuma anche che il regex non contenga alcun carattere di nuova riga non elaborato.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Oh, è vero, ero convinto che non ci sarebbero stati caratteri non stampabili nell'input. Lo risolverò una volta che avremo chiarimenti dal PO. (Se possono apparire dei personaggi, ci sono ancora alcune combinazioni che non appariranno in ciò che questa sfida considera una regex valida, ad esempio ]]], quindi in entrambi i casi, questa risposta non avrà bisogno di molte modifiche.)
Martin Ender

fatto golf dopo oltre un anno? : P
Okx,

2

JavaScript ES6, 574 byte

Probabilmente posso rimuovere alcune vardichiarazioni.

R=e=>{for(var s=0,c=[],h=/(\?|\+|\{\d*,*\d*\}|\*)(\?*)/,t=0;t<e.length;t++)switch(s){case 0:switch(e[t]){case"\\":t++,c.push("\\"+e[t]);break;case"[":j=t,s=1;break;case"(":k=t,s=2;break;default:var l=e.search(h,t);(l>=t+1||0>l)&&c.push(l==t+1?e[t]+e.slice(t,e.length).match(h)[0]:e[t])}break;case 1:"\\"==e[t]?t++:"]"==e[t]&&(c.push(e.slice(j,t+1)+(e.search(h,t)==t+1?e.slice(t,e.length).match(h)[0]:"")),s=0);break;case 2:"\\"==e[t]?t++:")"==e[t]&&(a=R(e.slice(k+1,t)),c.push("("+a+")"),s=0)}c.reverse(),r=c;var i=c.length-1;return"^"==c[i]&&(r[i]="$"),"$"==c[0]&&(r[0]="^"),r.join``}}

JS ES6, non testato, 559 byte

Testerà a casa.

R=e=>{for(s=0,c=[],h=/(\?|\+|\{\d*,*\d*\}|\*)(\?*)/,t=0;t<e.length;t++)switch(s){case 0:switch(e[t]){case"\\":t++,c.push`\\${e[t]}`;break;case"[":j=t,s=1;break;case"(":k=t,s=2;break;default:l=e.search(h,t);(l>=t+1||0>l)&&c.push(l==t+1?e[t]+e.slice(t,e.length).match(h)[0]:e[t])}break;case 1:"\\"==e[t]?t++:"]"==e[t]&&(c.push(e.slice(j,t+1)+(e.search(h,t)==t+1?e.slice(t,e.length).match(h)[0]:"")),s=0);break;case 2:"\\"==e[t]?t++:")"==e[t]&&(a=R(e.slice(k+1,t)),c.push`(${a})`,s=0)}c.reverse(),r=c;i=c.length-1;return"^"==c[i]&&(r[i]="$"),"$"==c[0]&&(r[0]="^"),r.join``}}

JavaScript ES5, non modificato, 961 byte

function revRegex(str){
 var mode = 0;
 var oS = [];
 var post = /(\?|\+|\{\d*,*\d*\}|\*)(\?*)/;
 for(var i=0;i<str.length;i++){
  switch(mode){
   case 0: switch(str[i]){
    case "\\": i++; oS.push("\\"+str[i]); break;
    case "[": j=i; mode = 1; break;
    case "(": k=i; mode = 2; break;
    default:
     var pLoc = str.search(post,i);
     if(pLoc>=i+1||pLoc<0){ // current is not pLoc
      if(pLoc==i+1){
       oS.push(str[i] + str.slice(i,str.length).match(post)[0]);
      } else {
       oS.push(str[i]);
      }
     }
   }; break;
   case 1: if(str[i]=="\\") i++; else if(str[i]=="]"){oS.push

(str.slice(j,i+1)+(str.search(post,i)==i+1?str.slice

(i,str.length).match(post)[0]:""));mode = 0}; break;
   case 2: if(str[i]=="\\") i++; else if(str[i]==")")

{a=revRegex(str.slice(k+1,i));oS.push("("+a+")");mode = 

0};break;
  }
 }
 oS.reverse();
 r=oS;
 var l=oS.length-1;
 if(oS[l]=="^") r[l]="$";
 if(oS[0]=="$") r[0]="^";
 return r.join("");
}

5
lol, hai usato regex per invertire regex: D
Kritixi Lithos

3
@ ΚριτικσιΛίθος Sì, l'ho fatto: D Lo userei per analizzare l'HTML se potessi ...
Conor O'Brien,

4
"se potessi"
Ottimizzatore del

1
@ CᴏɴᴏʀO'Bʀɪᴇɴ ho analizzato i codici html con regex ma ho avuto un serio problema con i caratteri unicode
Abr001am

2
@ CᴏɴᴏʀO'Bʀɪᴇɴ Questa è un'alternativa: `code.replace (/.*/," trollolol ");
Kritixi Lithos,

2

JavaScript ES6, 343 byte

t=r=>(u="substr",T="(?:[+?*]|{\\d+(?:,\\d*)?})?)([^]*)",(c=r[0])=="(")?([n,s]=v(r[u](1)),[_,q,s]=s.match("^(\\)"+T),["("+n+q,s]):c==")"||c==null?["",r]:c=="^"?["^",r[u](1)]:c=="$"?["^",r[u](1)]:r.match("^("+/(?:\[(?:[^\]\\]|\\[^])*\]|[^[\\]|\\[^])/.source+T).slice(1);(v=r=>{var o="";do{[n,r]=t(r);o=n+o;}while(n&&r);return[o,r]})(prompt())[0]

Codice originale (le funzioni, ma senza prompt):

function reverse(regex) {
    var out = "";
    do {
        // console.log("calling term");
        var [node, regex] = term(regex);
        // console.log("reverse: " + [node, regex]);
        out = node + out;
    } while (node && regex);
    return [out, regex];
}

function term(regex) {
    switch (regex[0]) {
        case "(":
            // console.log("calling reverse");
            var [node, sequel] = reverse(regex.substr(1));
            // console.log("term: " + regex + " / " + [node, sequel]);
            var [_, quantifier, sequel] = sequel.match(/^(\)(?:[+?*]|{\d+(?:,\d*)?})?)([^]*)/);
            return ["(" + node + quantifier, sequel];
        case ")":
        case void 0:
            return ["", regex];
        case "^":
            return ["$", regex.substr(1)];
        case "$":
            return ["^", regex.substr(1)];
        default:
            return regex.match(/^((?:\[(?:[^\]\\]|\\[^])*\]|[^[\\]|\\[^])(?:[+?*]|{\d+(?:,\d+)?})?)([^]*)/).slice(1);
    }
}

reverse("^\\(([The(){}*\\] ]{2,3}world\\\\(begin(ner|ning)?|ends*)+|Con\\|ti\\*n\\)ue...[^%\\[\\]()\\\\])$")[0]

Il codice è implementato come un parser top-down ricorsivo, quindi può causare lo overflow dello stack su input profondamente nidificati.

Il codice può causare un ciclo infinito in casi non validi, poiché non li collaudo, sfruttando la clausola "comportamento indefinito".


0

Python 3, 144 byte

(Questo non supporta i qualificatori su un gruppo come (a)+(b)*(cde)?.)

import re;f=lambda x:''.join({e:e,'^':'$','$':'^','(':')',')':'('}[e]for e in re.findall(r'(?:\\.|\[(?:\\?.)+?\]|.)(?:[?+*]|\{.+?\})?',x)[::-1])

Casi test:

test_cases = [
    # Provided test cases
    r'abc',
    r'tuv?',
    r'a(b|c)',
    r'1[23]',
    r'a([bc]|cd)',
    r'^a[^bc]d$',
    r'x[yz]{1,2}',
    r'p{2}',
    r'q{7,}',
    r'\[c[de]',

    # Pathological cases
    r'a{3}b',
    r'(a)?(b)+',            # <-- currently failing!
    r'[\[]{5}[^\]]{6}',
    r'[\[]\]{7}',
    r'[\[\]]{8,9}',
    r'\(\)\^\$',

    # Undefined cases
    r'ab[c',
    r'a(?bc)',
    r'a[]]bc',
]

for t in test_cases:
    print(t, '->', f(t))

Risultato:

abc -> cba
tuv? -> v?ut
a(b|c) -> (c|b)a
1[23] -> [23]1
a([bc]|cd) -> (dc|[bc])a
^a[^bc]d$ -> ^d[^bc]a$
x[yz]{1,2} -> [yz]{1,2}x
p{2} -> p{2}
q{7,} -> q{7,}
\[c[de] -> [de]c\[
a{3}b -> ba{3}
(a)?(b)+ -> )+b))?a)                    # <-- note: wrong
[\[]{5}[^\]]{6} -> [^\]]{6}[\[]{5}
[\[]\]{7} -> \]{7}[\[]
[\[\]]{8,9} -> [\[\]]{8,9}
\(\)\^\$ -> \$\^\)\(
ab[c -> c[ba
a(?bc) -> (cb(?a
a[]]bc -> cb[]]a
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.