Регекс у зворотному порядку - розкладіть регулярні вирази


17

Проблема

У мене є маса регулярних виразів, які мені потрібно використовувати в якомусь коді, але я використовую мову програмування, яка не підтримує регулярний вираз! На щастя, я знаю, що тестова рядок матиме максимальну довжину і буде складатися тільки з друкованого ASCII.

Змагання

Ви повинні ввести регулярний вираз і число n, і вихід кожен рядок складається з друкованої ASCII (ASCII коди від 32 до 126 включно, до ~, ні вкладок або перекладу рядка) довжини менше або дорівнює nщо збігається з регулярним виразом. Ви взагалі не можете використовувати вбудовані регулярні вирази або функції зіставлення регулярних виразів у своєму коді. Регулярні вирази обмежуватимуться наступним:

  • Літеральні символи (і втечі, які змушують персонажа бути буквальним, так \.це буквальний ., \nє буквальним n(еквівалентний справедливому n) і \wеквівалентний w. Вам не потрібно підтримувати послідовності втечі.)
  • . - підстановочний знак (будь-який символ)
  • Класи символів [abc]означає "a або b або c" і [d-f]означає що-небудь від d до f (так, d або e або f). Єдиними символами, які мають особливе значення у класі символів, є [і ](які завжди будуть уникнути, тому не хвилюйтеся про них), \(звичайно, символ втечі), ^на початку класу символів (що є запереченням ), і -(що є діапазоном).
  • |- оператор АБО, чергування. foo|barкошти або fooабо bar, і (ab|cd)eматчі або abeабо cde.
  • * - відповідати попередньому жетону, повтореному нулю або більше разів, жадібним (він намагається повторити якомога більше разів)
  • + - повторював один чи кілька разів жадібний
  • ? - нуль або один раз
  • Угруповання з допомогою дужок, групувати жетони |, *. +, або?

Вхід регулярний вираз завжди буде дійсним (тобто, ви не повинні обробляти введення як ?abcабо (fooчи будь-який невірний введення). Ви можете виводити рядки в будь-якому бажаному порядку, але кожен рядок повинен з’являтися лише один раз (не виводити жодних дублікатів).

Випробування

Вхід: .*, 1
вихід: (порожній рядок), , !, ", ..., },~

Вхід: w\w+, 3
вихід: ww,www

Вхід: [abx-z][^ -}][\\], 3
вихід: a~\, b~\, x~\, y~\,z~\

Вхід: ab*a|c[de]*, 3
вихід: c, cd, ce, aa, cde, ced, cdd, cee,aba

Вхід: (foo)+(bar)?!?, 6
вихід: foo, foo!, foofoo,foobar

Вхід: (a+|b*c)d, 4
вихід: ad, cd, aad, bcd, aaad,bbcd

Вхід: p+cg, 4
вихід: pcg,ppcg

Вхід: a{3}, 4
вихід:a{3}

Переможець

Це , тому найкоротший код у байтах виграє!


Чи дозволяється нам підтримувати послідовності втечі? Тоді це банально.
Джон Дворак

3
Ваше пояснення |має дуже мало сенсу. Схоже, це не обробляє вкладені групи або a|b|c. Що поганого у використанні стандартних пояснень щодо того, наскільки сильно пов'язують конкатенацію та чергування? (І у вас немає виправдань за те, щоб не скористатися пісочницею)
Пітер Тейлор

1
@PeterTaylor Насправді у нього є виправдання: meta.codegolf.stackexchange.com/q/1305/9498
Джастін

2
Судячи з вашого прикладу, шаблон повинен відповідати всій рядку? (На відміну від підрядка)
Мартін Ендер

3
@KyleKanos Прикро, що реальні проблеми у світі не змушують вас думати, що вам слід вчити регулярні вирази. : P Але вони не такі важкодоступні, як може здатися: regular-expressions.info/tutorial.html
Martin Ender

Відповіді:


8

Haskell 757 705 700 692 679 667

import Data.List
data R=L Char|A R R|T R R|E
h=[' '..'~']
k(']':s)a=(a,s)
k('^':s)_=l$k[]s
k('-':c:s)(a:b)=k([a..c]++b)s
k('\\':c:s)a=k s$c:a
k(c:s)a=k s$c:a
l(a,b)=(h\\a,b)
c#E=L c
c#r=A(L c)r
o(a,b)=(foldr(#)E a,b)
t%0=E
t%n=A(t%(n-1))$T t$t%(n-1)
d s n=m(fst$r s)[[]] where{m E a=a;m(L c)a=[b++[c]|b<-a,length b<n];m(A r s)x=nub$(m r x)++m s x;m(T r s)a=m s$m r a;r s=w$e s E;w(u,'|':v)=(\(a,b)->(A u a,b))$r v;w x=x;e(')':xs)t=(t,xs);e s@('|':_)t=(t,s);e s@(c:_)t=g t$f$b s;e[]t=(t,[]);g t(u,v)=e v$T t u;f(t,'*':s)=(t%n,s);f(t,'+':s)=(T t$t%n,s);f(t,'?':s)=(A t E,s);f(t,s)=(t,s);b('(':s)=r s;b('\\':s:t)=(L s,t);b('.':s)=o(h,s);b('[':s)=o$k s[];b(s:t)=(L s,t)}

вихід:

ghci> d ".*" 1
[""," ","!","\"","#","$","%","&","'","(",")","*","+",",","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~"]
ghci> d "w\\w+" 3
["ww","www"]
ghci> d "[abx-z][^ -}][\\\\]" 3
["x~\\","y~\\","z~\\","b~\\","a~\\"]
ghci> d "ab*a|c[de]*" 3
["aa","aba","c","ce","cd","cee","cde","ced","cdd"]
ghci> d "(foo)+(bar)?!?" 6
["foo!","foobar","foo","foofoo"]
ghci> d "(a+|b*c)d" 4
["ad","aad","aaad","cd","bcd","bbcd"]
ghci> d "p+cg" 4
["pcg","ppcg"]
ghci> d "a{3}" 4
["a{3}"]

Пояснення: це реалізація підручника підручника. R - тип регулярного виразів з конструкторами A (поперемінний), L (буквальний), T (тоді) та E (порожній / епсилон). Звичайна "Зірка" не відображається, тому що я вказую її як чергування під час розбору (див. "%"). 'm' запускає моделювання. Парсер (початок з 'rs = ....') - це просто рекурсивний спуск; 'k' розбирає діапазони. Функція "#" розширює діапазони на чергування.


9

Python v2.7 1069 1036 950 925 897 884 871 833 822

Ця відповідь здається досить довгою для кодового гольфу, але є багато операторів, з якими потрібно оброблятись, і я знаю, з якою метою виконує кожен байт у цій відповіді. Оскільки відповіді немає, я подаю це як ціль, щоб інші користувачі перемогли. Подивіться, чи можете ви зробити коротку відповідь :).

Дві основні функції - це те, fщо аналізує регекс, починаючи з iго символу, і dякий генерує відповідні рядки, використовуючи rпідрегекси, в які ми можемо повторити, 'a' масив, що представляє ще не оброблену частину поточного підрегексу, і суффікс рядка, sякий представляє частину рядка, сформовану дотепер.

Також перевірте вихідний зразок і тестовий джгут .

import sys;V=sys.argv;n=int(V[2]);r=V[1];S=len;R=range;C=R(32,127)
Z=[];z=-1;D='d(r,p,';F='for j in '
def f(i,a):
 if i>=S(r):return a,i
 c=r[i];x=0;I="|)]".find(c)
 if c in"([|":x,i=f(i+1,Z)
 if I+1:return([c,a,x],[a],[c,a])[I],i
 if'\\'==c:i+=1;x=c+r[i]
 return f(i+1,a+[x or c])
def d(r,a,s):
 if S(s)>n:return
 while a==Z:
        if r==Z:print s;return
        a=r[z];r=r[:z]
 e=a[z];p=a[0:z]
 if'|'==a[0]:d(r,a[1],s);d(r,a[2],s)
 elif']'==a[0]:
        g=a[1];N=g[0]=='^';g=(g,g[1:])[N];B=[0]*127;O=[ord(c[z])for c in g]
        for i in R(0,S(g)):
         if'-'==g[i]:exec F+'R(O[i-1],O[i+1]):B[j]=1'
         else:B[O[i]]=1
        for c in C:N^B[c]<1or d(r,Z,chr(c)+s)
 elif' '>e:d(r+[p],e,s)
 else:c=p[:z];exec{'.':F+'C:'+D+'chr(j)+s)','?':D+'s);d(r,p[:z],s)','*':F+'R(0,n+1):d(r,c,s);c+=[p[z]]','+':"d(r,p+['*',p[z]],s)"}.get(e,D+'e[z]+s)')
d(Z,f(0,Z)[0],"")

Зауважте, що вкладки в оригінальному рішенні були expandвідредаговані. Для підрахунку кількості символів у початковому використанні unexpand < regex.py | wc.


9
Я ніколи не бачив пітона вид , що жахливо.
user80551

Хіба ви не можете змінити , def E(a,b):c=a[:];c.extend(b);return cщоб E=lambda a,b:a[:].extend(b), те ж саме дляA
user80551

Мабуть, ні, оскільки .extend (b) нічого не повертає.
gmatht

1
Для того elif isinstance(e,str):, я вважаю, що ви можете змінити код усередині на: exec{'.':'for c in C:d(r,p,s+chr(c))','?':'d(r,p,s);d(r,p[:z],s)','*':'''c=p[:z]#newline for i in R(0,n+1):d(r,c,s);c+=[p[z]]''','+':"d(r,p+['*',p[z]],s)",'\\':'d(r,p,e[1]+s)'}.get(e,'d(r,p,e+s)')(зауважте, що #newlineце новий рядок) (джерело: stackoverflow.com/a/103081/1896169 )
Джастін

1
Якщо ви зможете знайти більше місць для використання трюку exec, ми зможемо легко змінити ваш код на нечитабельний код :-)
Джастін

1

Пролог (SWI) , 586 байт

Вбудована здатність зворотного відстеження Prolog робить його приголомшливим вибором для цього завдання. Користуючись зворотним відстеженням, генерування рядків для регулярного вираження стає точно таким же завданням, як і тестування, якщо рядок узгоджується з регулярним виразом. На жаль, багато моїх зусиль з гольфу пішло на написання коротших парсекс-симуляторів. Справжнє завдання розкласти звичайний вираз ми легко переграли.

R-L-S:-R*A,-(B,A,[]),setof(Z,(0/L/M,length(C,M),C+B+[],Z*C),S).
-R-->e+S,S-R.
R-T-->{R=T};"|",e+S,u+R+S-T.
Z+Y-->(".",{setof(C,32/126/C,R)};"[^",!,\E,"]",{setof(C,(32/126/C,\+C^E),R)};"[",\R,"]";"(",-R,")";{R=[C]},([C],{\+C^`\\.[|+?*(`};[92,C])),("*",{S=k*R};"+",{S=c+R+k*R};"?",{S=u+e+R};{S=R}),({Y=c+Z+S};c+Z+S+Y).
\C-->{C=[H|T]},+H,\T;{C=[]};+A,"-",+B,\T,{setof(C,A/B/C,H),append(H,T,C)}.
+C-->[92,C];[C],{\+C^`\\]-`}.
S+e+S.
[C|S]+D+S:-C^D.
S+(B+L+R)+T:-B=c,!,S+L+U,U+R+T;S+L+T;S+R+T.
S+k*K+U:-S=U;S+K+T,S\=T,T+k*K+U.
A/B/C:-between(A,B,C).
A^B:-member(A,B).
A*B:-string_codes(A,B).

Спробуйте в Інтернеті!

Кодекс без вольфів

generate_string(R, L, S) :-
    % parse regex
    string_codes(R, RC),
    regex_union(RE, RC, []),

    % bound string length
    between(0, L, M),
    length(SC, M),

    % find string
    match(SC, RE, []),

    string_codes(S, SC).

% Parsers
%%%%%%%%%  

regex_union(R) -->regex_concat(S), regex_union1(S, R).

regex_union1(R,T) --> [124], regex_concat(S), regex_union1(regex_union(R,S), T).
regex_union1(R, R) --> [].

regex_concat(R) --> regex_op(S), regex_concat1(S, R).

regex_concat1(R, T) --> regex_op(S), regex_concat1(regex_concat(R,S), T).
regex_concat1(R, R) --> [].

regex_op(regex_kleene(R)) --> regex_lit(R), [42].
regex_op(regex_concat(R,regex_kleene(R))) --> regex_lit(R), [43].
regex_op(regex_union(regex_empty,R)) --> regex_lit(R), [63].
regex_op(R) --> regex_lit(R).

regex_lit(regex_char([C])) --> [C], {\+ regex_ctrl(C)}.
regex_lit(regex_char([C])) --> [92], [C].

regex_lit(regex_char(CS)) --> [46], {findall(C, between(32,126, C), CS)}.

regex_lit(regex_char(DS)) --> 
    [91], [94], !, class_body(CS), [93],
    {findall(C, (between(32, 126, C), \+ member(C, CS)), DS)}.
regex_lit(regex_char(CS)) --> [91], class_body(CS), [93].

regex_lit(R) --> [40], regex_union(R), [41].

class_body([C|T]) --> class_lit(C),class_body(T).
class_body(CS) -->
    class_lit(C0), [45], class_lit(C1), class_body(T),
    {findall(C, between(C0, C1, C), H), append(H,T,CS)}.
class_body([]) --> [].

class_lit(C) --> [C], {\+ class_ctrl(C)}.
class_lit(C) --> [92], [C].

class_ctrl(C) :- string_codes("\\[]-", CS), member(C, CS).
regex_ctrl(C) :- string_codes("\\.[]|+?*()", CS), member(C, CS).

% Regex Engine
%%%%%%%%%%%%%% 

% The regex empty matches any string without consuming any characters.
match(S, regex_empty, S).

% A regex consisting of a single character matches any string starting with
% that character. The chanter is consumed.
match([C|S], regex_char(CS), S) :- member(C, CS).

% A union of two regex only needs to satisify one of the branches.
match(S, regex_union(L,R), T) :- match(S, L, T); match(S, R, T).     

% A concat of two regex must satisfy the left and then the right.
match(S, regex_concat(L, R), U) :- match(S, L, T), match(T, R, U).

% The kleene closure of a regex can match the regex 0 times or it can the regex
% once before matching the kleene closure again.
match(S, regex_kleene(_), S).
match(S, regex_kleene(K), U) :- match(S, K, T), S \= T, match(T, regex_kleene(K), U).

Я не знайомий з DCG Prolog, як це regex_union(RE, RC, [])відповідає regex_union(R) -->...?
Kritixi Lithos

@KritixiLithos DCG-предикати мають два неявні параметри, які подаються автоматично при виклику з DCG або як частини phrase\2. Перший - рядок, до якого застосовується DCG, а другий - деякий суфікс рядка, який залишається після задоволення предиката DCG. Еквівалентна конструкція була б phrase(regex_union(RE), RC).
ankh-morpork

До речі, вам може бути цікаво вирішити codegolf.stackexchange.com/q/161108 , виклик вимагає більш простого регексу, тому розбір буде простішим, і це звучить як щось, що пролог може зробити прекрасно
Kritixi Lithos
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.