Normalde ters ifade - düzenli ifadeleri ayrıştır


18

Sorun

Bazı kod kullanmanız gereken düzenli ifadeler bir demet var, ama regex desteklemeyen bir programlama dili kullanıyorum! Neyse ki, test dizesinin maksimum uzunluğa sahip olacağını ve sadece yazdırılabilir ASCII'den oluşacağını biliyorum.

Meydan okuma

Girmelisiniz regex ve bir sayı nve çıkış yazdırılabilir ASCII (ASCII kodları 32 dahil 126 kadar oluşan her dize için ~daha az ya da eşit uzunlukta, hiçbir sekme veya yeni satırlar) nregex o maçları. Sen olabilir değil yerleşik kullanmak normal ifadeler veya regex eşleştirme fonksiyonları kodunuzda hiç. Normal ifadeler aşağıdakilerle sınırlı olacaktır:

  • Değişmez karakterler (ve bir karakteri değişmez olmaya zorlayan kaçar, yani \.değişmezdir ., \ndeğişmezdir n(sadece ile eşdeğerdir n) ve \weşdeğerdir w. Kaçış dizilerini desteklemenize gerek yoktur.)
  • . - joker karakter (herhangi bir karakter)
  • Karakter sınıfları, [abc]"a veya b veya c" [d-f]anlamına gelir ve d'den f'ye kadar olan herhangi bir şey anlamına gelir (yani, d veya e veya f). Bir karakter sınıfında özel anlamı olan tek karakterler [ve ](her zaman \kaçacak , bu yüzden endişelenmeyin), (tabii ki kaçış karakteri), ^karakter sınıfının başında (bu bir olumsuzlamadır) ) ve -(bu bir aralıktır).
  • |- VEYA operatörü, dönüşüm. foo|bararaca ya fooya bar, ve (ab|cd)emaçları ya abeya cde.
  • * - önceki jetonu sıfır veya daha fazla kez tekrarlayın, açgözlü (mümkün olduğunca çok kez tekrarlamaya çalışır)
  • + - bir veya daha fazla kez tekrarlandı, açgözlü
  • ? - sıfır veya bir kez
  • Grup belirteçleri, parantez ile gruplandırma |, *. +veya?

Giriş regex her zaman geçerli olacak (yani sizin gibi girdi işlemek gerekmiyor ?abcya (fooya da herhangi bir geçersiz giriş). Dizeleri istediğiniz sırada verebilirsiniz, ancak her dize yalnızca bir kez görünmelidir (yinelenen çıktılar almayın).

Test Durumları

Girdi: .*, 1
Çıktı: (boş dize), , !, ", ..., },~

Girdi: w\w+, 3
Çıktı: ww,www

Girdi: [abx-z][^ -}][\\], 3
Çıktı: a~\, b~\, x~\, y~\,z~\

Girdi: ab*a|c[de]*, 3
Çıktı: c, cd, ce, aa, cde, ced, cdd, cee,aba

Girdi: (foo)+(bar)?!?, 6
Çıktı: foo, foo!, foofoo,foobar

Girdi: (a+|b*c)d, 4
Çıktı: ad, cd, aad, bcd, aaad,bbcd

Girdi: p+cg, 4
Çıktı: pcg,ppcg

Girdi: a{3}, 4
Çıktı:a{3}

Kazanan

Bu , bu yüzden bayt içindeki en kısa kod kazanacak!


Kaçış dizilerini desteklememize izin var mı? O zaman bu önemsizdir.
John Dvorak

3
Açıklamanız |çok az mantıklı. İç içe gruplarla ilgilenmiyor gibi görünüyor a|b|c. Birleştirmenin ve alternatifin ne kadar güçlü bir şekilde bağlandığına ilişkin standart açıklamaları kullanmanın yanlışlığı nedir? (Ve sen sandbox'ı kullanmamak için hiçbir bahane)
Peter Taylor

1
@PeterTaylor Aslında, bir bahanesi var: meta.codegolf.stackexchange.com/q/1305/9498
Justin

2
Örneğinize bakarak, tüm dizeyle eşleşmesi gerekir mi? (Bir alt dize aksine)
Martin Ender

3
@KyleKanos Utanç verici gerçek dünya sorunları, düzenli ifadeler öğrenmeniz gerektiğini düşündürmüyor. : P Ama göründükleri kadar erişilemez değiller: regular-expressions.info/tutorial.html
Martin Ender

Yanıtlar:


8

Haskell 757705 700626679677

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)}

çıktı:

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}"]

Açıklama: Bu bir ders kitabı normal ifade uygulamasıdır. R, A (alternatif), L (değişmez), T (sonra) ve E (boş / epsilon) yapıcıları ile normal ifade tipidir. Her zamanki 'Yıldız' görünmüyor çünkü ayrıştırma sırasında alternatifler olarak satır içi yapıyorum (bkz. '%'). 'm' simülasyonu çalıştırır. Ayrıştırıcı ('rs = ....' ile başlayın) sadece özyinelemeli iniş; 'k' aralıkları ayrıştırır. '#' İşlevi, aralıkları dönüşümlü olarak genişletir.


9

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

Bu cevap bir kod golf için oldukça uzun görünüyor, ancak ele alınması gereken çok sayıda operatör var ve bu cevaptaki her baytın hangi amacı yaptığını biliyorum. Mevcut bir cevap olmadığından, bunu diğer kullanıcıların yenmesi için bir hedef olarak gönderiyorum. Daha kısa bir cevap yapıp yapamayacağınıza bakın :).

İki ana işlev f, ith karakterinden başlayarak regex'i ayrıştıran ve tekrarlayabildiğimiz alt regex'leri dkullanarak eşleşen dizeleri üreten, rşu anda henüz devam edilmemiş olan alt regex'in bölümünü temsil eden dizi, ve sşimdiye kadar oluşturulan dizenin bölümünü temsil eden bir dize soneki .

Ayrıca numune çıkışını ve bir test kayışını kontrol edin .

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],"")

Orijinal çözümdeki sekmelerin expanddüzenlendiğini unutmayın. Orijinal kullanımdaki karakter sayısını saymak için unexpand < regex.py | wc.


9
Hiç bu kadar korkunç göründüğünü hiç görmedim .
user80551

Eğer değiştirilemiyor def E(a,b):c=a[:];c.extend(b);return ciçin E=lambda a,b:a[:].extend(b), aynen içinA
user80551

Görünüşe göre, .extend (b) hiçbir şey döndürmediği için.
gmatht

1
İçin, elif isinstance(e,str):içindeki kodu değiştirebileceğinize inanıyorum: 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)')( #newlinebir yeni satır olduğuna dikkat edin ) (kaynak: stackoverflow.com/a/103081/1896169 )
Justin

1
Exec hile kullanmak için daha fazla yer bulabilirseniz, kodunuzu kolayca okunamaz koda dönüştürebiliriz :-)
Justin

1

Prolog (SWI) , 586 bayt

Prolog'un yerleşik geri izleme yeteneği, bu meydan okuma için harika bir seçimdir. Geri izlemeden yararlanarak, normal ifade için dizeler oluşturmak, dizenin normal ifadeyle eşleşip eşleşmediğini test etmekle aynı görev haline gelir. Ne yazık ki, golf çabalarımın çoğu daha kısa regex ayrıştırıcıları yazmaya başladı. Düzenli bir ifadeyi çürütmenin asıl görevi kolayca golf oynadık.

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).

Çevrimiçi deneyin!

Açık Kod

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).

Prolog DCG'lere aşina değilim, regex_union(RE, RC, [])eşleşmeye karşı nasıl regex_union(R) -->...?
Kritixi Lithos

@KritixiLithos DCG tahminleri, bir DCG içinden veya bir parçası olarak çağrıldığında otomatik olarak sağlanan iki örtük parametreye sahiptir phrase\2. Birincisi DCG'nin uygulandığı dize, ikincisi DCG yüklemini karşıladıktan sonra kalan dizenin bir sonekidir. Eşdeğer bir yapı olurdu phrase(regex_union(RE), RC).
ankh-morpork

Bu arada, codegolf.stackexchange.com/q/161108'i çözmek isteyebilirsiniz , meydan okuma daha basit bir regex ister, bu nedenle ayrıştırma daha kolay olurdu ve bu,
prologun

@KritixiLithos evet, normal ifade tamamlayıcı kesinlikle ilginç bir görev. Normal ifade-> nfa-> dfa-> tamamlayıcı-> normal ifade boru hattını uyguladım ve tam olarak kısa değil. Göndermeden önce biraz daha kısa uygulamalara bakmak istiyorum.
ankh-morpork

Ben kaba kuvvet kullanarak bu konuya girmeye çalışıyorum; Aklımda bir algoritma var, ancak prologda kaba kuvvet kısmını uygulamak şimdiye kadar başarılı olmadı. Hm, normal ifade <=> dfa dönüştürmek için tersinir bir yüklem varsa iyi olurdu. Her iki çözümümüzden ne geldiğini görmek ilginç
Kritixi Lithos
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.