정규식 반대로-정규식 분해


16

문제

일부 코드에서 사용해야하는 정규식이 많이 있지만 정규식을 지원하지 않는 프로그래밍 언어를 사용하고 있습니다! 운 좋게도 테스트 문자열의 길이는 최대 길이이며 인쇄 가능한 ASCII로만 구성됨을 알고 있습니다.

도전

사용자 입력해야 정규식과 개수 n및 출력 인쇄 ASCII (ASCII 코드 (32)를 포함한 126, 구성된 모든 문자열 ~에 이하인 길이없이 탭이나 개행) n정규식과 일치하는. 코드에 내장 정규식이나 정규식 일치 함수를 전혀 사용할 수 없습니다 . 정규식은 다음으로 제한됩니다.

  • 리터럴 문자 (문자를 강제 탈출, 그래서, 문자 그대로하는 \.리터럴 ., \n리터럴 n단지에 해당 ( n)와 \w동일합니다 w당신은 지원 이스케이프 시퀀스에 필요하지 않습니다.).
  • . -와일드 카드 (모든 문자)
  • 문자 클래스 [abc]는 "a 또는 b 또는 c"를 [d-f]의미하며 d에서 f까지 (즉, d 또는 e 또는 f)를 의미합니다. 문자 클래스에서 특별한 의미를 가지고있는 유일한 문자는 [](항상 탈출 할 것이다, 그래서 그들에 대해 걱정하지 할), \(이스케이프 문자, 물론), ^부정 인 문자 클래스의 시작 (에 ) 및 -(범위)입니다.
  • |-OR 연산자, 교대 foo|bar수단 중 하나 foo또는 bar(ab|cd)e일치하거나 abe또는 cde.
  • * -이전 토큰을 0 번 이상 반복, 욕심과 일치시킵니다 (가능한 한 여러 번 반복하려고 함)
  • + -탐욕스럽고 여러 번 반복
  • ? -0 회 또는 1 회
  • 대한 그룹 토큰에 괄호로 그룹화 |, *. +또는?

입력 정규식은 항상 유효합니다 (즉, 당신은 같은 입력을 처리 할 필요가 없다 ?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}

승자

이것은 이므로 바이트 단위의 가장 짧은 코드가 이길 것입니다!


이스케이프 시퀀스를 지원할 수 있습니까? 그렇다면 이것은 사소한 것입니다.
John Dvorak

3
당신의 설명은 |거의 이해가되지 않습니다. 중첩 그룹 또는을 처리하지 않는 것 같습니다 a|b|c. 연결과 변경이 얼마나 강력하게 묶이는가에 대한 표준 설명을 사용하면 무엇이 문제입니까? (그리고 당신 은 샌드 박스를 사용하지 않은 것에 대한 변명의 여지가 없습니다)
Peter Taylor

1
@PeterTaylor 사실, 그는 변명의 여지가있다 : meta.codegolf.stackexchange.com/q/1305/9498
Justin

2
예제로 판단하면 패턴이 전체 문자열과 일치해야합니까? (하위 문자열과 반대)
Martin Ender

3
@KyleKanos 현실 세계의 문제로 인해 정규 표현식을 배워야한다고 생각하지는 않습니다. : P 그러나 그들은 보이는 것처럼 접근하기가 쉽지 않다 : regular-expressions.info/tutorial.html
Martin Ender

답변:


7

하스켈 757705700 692679667

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 (빈 / 엡실론)가있는 정규식 유형입니다. 구문 분석 중에 교대로 인라인하기 때문에 일반적인 'Star'는 나타나지 않습니다 ( '%'참조). 'm'은 시뮬레이션을 실행합니다. 파서 ( 'rs = ....'에서 시작)는 재귀 적 하강입니다. 'k'는 범위를 구문 분석합니다. '#'함수는 범위를 교대로 확장합니다.


7

파이썬 V2.7 1,069 1,036 950 925 897 884 871 833 822

이 답변은 코드 골프에는 다소 오래 걸리지 만 처리해야 할 연산자가 많으며이 답변의 각 바이트가 어떤 용도로 사용되는지 알고 있습니다. 기존 답변이 없으므로 다른 사용자가 이길 수있는 대상으로 제출하십시오. 더 짧은 대답을 할 수 있는지 확인하십시오 :).

두 가지 주요 기능은 문자 f에서 시작하는 정규 표현식을 구문 분석하고 재귀 할 수있는 하위 정규 표현식 을 사용하여 일치하는 문자열을 생성하는 것입니다 .'a '아직 처리되지 않은 현재 하위 정규 표현식의 일부를 나타내는 배열 및 지금까지 생성 된 문자열의 일부를 나타내는 문자열 접미사 .idrs

또한 샘플 출력테스트 하니스를 확인하십시오 .

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 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 )
저스틴

1
exec 트릭을 사용할 더 많은 곳을 찾을 수 있다면 코드를 읽을 수없는 코드로 쉽게 변경할 수 있습니다 :-)
Justin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.