逆の正規表現-正規表現を分解する


16

問題

いくつかのコードで使用する必要がある正規表現がたくさんありますが、正規表現をサポートしていないプログラミング言語を使用しています!幸いなことに、テスト文字列は最大長であり、印刷可能なASCIIのみで構成されることがわかっています。

チャレンジ

入力する必要があり、正規表現と数n、及び出力の印刷可能なASCII文字(ASCIIコード32包括的な126、から構成されるすべての文字列に対して~未満又は等しい長さの、ないタブや改行)n正規表現ものと一致します。コードで組み込みの正規表現または正規表現一致関数を使用することは一切できません。正規表現は次のものに制限されます。

  • リテラル文字(およびエスケープ、文字を強制的にリテラルにするため\.、リテラル.\nはリテラルn(ちょうどに相当n)、および\wに相当しwます。エスケープシーケンスをサポートする必要はありません。)
  • . -ワイルドカード(任意の文字)
  • 文字クラスは、[abc]「aまたはbまたはc」を[d-f]意味し、dからfまでのすべてを意味します(so、dまたはeまたはf)。文字クラスで特別な意味を持つ唯一の文字は[、および](常にエスケープされるため、それらを心配しないでください)、\(エスケープ文字、もちろん)、^文字クラスの先頭(否定です) )、および-(範囲です)。
  • |-OR演算子、交互。foo|bar手段のいずれかfooまたはbar、そして(ab|cd)e試合のいずれかabeまたはcde
  • * -貪欲に0回以上繰り返された前のトークンに一致します(可能な限り何度も繰り返します)
  • + -貪欲な1回以上の繰り返し
  • ? -0回または1回
  • のトークンをグループ化するために|、括弧でグループ化します*+、または?

入力正規表現は常に有効になります(つまり、あなたは次のように入力を処理する必要はありません?abcか、(fooまたは無効な入力)。任意の順序で文字列を出力できますが、各文字列は一度だけ表示する必要があります(重複を出力しないでください)。

テストケース

入力:.*1
出力:(空の文字列)、 、、 、...、 、!"}~

入力:w\w+3
出力:wwwww

入力:[abx-z][^ -}][\\]3
出力:a~\b~\x~\y~\z~\

入力:ab*a|c[de]*3
出力:ccdceaacdecedcddceeaba

入力:(foo)+(bar)?!?6
出力:foofoo!foofoofoobar

入力:(a+|b*c)d4
出力:adcdaadbcdaaadbbcd

入力:p+cg4
出力:pcgppcg

入力:a{3}4
出力:a{3}

勝者

これはなので、バイト単位の最短コードが勝ちます!


エスケープシーケンスをサポートできますか?その後、これは簡単です。
ジョンドヴォルザーク14

3
あなたの説明は|ほとんど意味がありません。ネストされたグループやを処理していないようですa|b|c。連結と交替のバインドの強さに関して標準的な説明を使用することの何が問題になっていますか?(そして、あなたはサンドボックスを使用していないための言い訳を持っていません)
ピーター・テイラー

1
@PeterTaylor実際、彼には言い訳があります:meta.codegolf.stackexchange.com/q/1305/9498
ジャスティン

2
あなたの例から判断すると、パターンは文字列全体と一致する必要がありますか?(部分文字列ではなく)
マーティンエンダー14

3
@KyleKanos実世界の問題は、正規表現を学ぶべきだと思わせないのは残念です。:Pしかし、見た目
マーティンエンダー

回答:


7

ハスケル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'は範囲を解析します。関数「#」は、範囲を交互に拡張します。


7

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

この答えはコードゴルフではかなり長いように見えますが、処理する必要のある演算子がたくさんあり、この答えの各バイトが何の目的であるかを知っています。既存の回答がないため、他のユーザーが勝つためのターゲットとしてこれを提出します。短い答えができるかどうかを確認してください:)。

2つの主な関数はfith文字から始まる正規表現を解析し、再帰可能なサブ正規表現を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
こんなに恐ろしいPythonを見たことはありません。
user80551 14

あなたは変更できませんdef E(a,b):c=a[:];c.extend(b);return cE=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
ジャスティン14

1
execトリックを使用する場所が他にある場合は、簡単にコードを判読不能なコードに変更できます:
Justin
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.