Regex ngược lại - phân tách các biểu thức chính quy


16

Vấn đề

Tôi có một loạt các biểu thức chính quy mà tôi cần sử dụng trong một số mã, nhưng tôi đang sử dụng ngôn ngữ lập trình không hỗ trợ regex! May mắn thay, tôi biết rằng chuỗi thử nghiệm sẽ có độ dài tối đa và sẽ chỉ bao gồm ASCII có thể in được.

Các thách thức

Bạn phải nhập một regex và một số n, và sản lượng mỗi chuỗi gồm ASCII in được (mã ASCII 32 đến 126, để ~, không có tab hoặc dòng mới) có chiều dài nhỏ hơn hoặc bằng để nmà trận đấu rằng regex. Bạn hoàn toàn không thể sử dụng các biểu thức chính quy hoặc các hàm so khớp regex tích hợp trong mã của mình. Biểu thức thông thường sẽ được giới hạn ở các mục sau:

  • Ký tự chữ (và thoát, mà buộc một nhân vật là nghĩa đen, vì vậy \.là một chữ ., \nlà một chữ n(tương đương với chỉ n), và \wtương đương với w. Bạn không cần phải trình tự hỗ trợ thoát.)
  • . - ký tự đại diện (bất kỳ ký tự nào)
  • Các lớp ký tự, [abc]có nghĩa là "a hoặc b hoặc c" và [d-f]có nghĩa là bất cứ thứ gì từ d đến f (vì vậy, d hoặc e hoặc f). Các ký tự duy nhất có ý nghĩa đặc biệt trong một lớp nhân vật là [](sẽ luôn luôn được thoát, vì vậy đừng lo lắng về chúng), \(nhân vật thoát, tất nhiên), ^ở đầu lớp nhân vật (đó là một phủ định ) và -(là một phạm vi).
  • |- toán tử OR, xen kẽ. foo|barcó nghĩa là foohoặc bar, và (ab|cd)ekhớp hoặc abehoặc cde.
  • * - khớp với mã thông báo trước đó lặp đi lặp lại 0 lần hoặc nhiều lần, tham lam (nó cố gắng lặp lại nhiều lần nhất có thể)
  • + - lặp đi lặp lại một hoặc nhiều lần, tham lam
  • ? - không hoặc một lần
  • Nhóm với dấu ngoặc đơn, để tokens nhóm cho |, *. +, hoặc là?

Regex đầu vào sẽ luôn hợp lệ (nghĩa là bạn không phải xử lý đầu vào như ?abchoặc (foohoặc bất kỳ đầu vào không hợp lệ nào). Bạn có thể xuất các chuỗi theo bất kỳ thứ tự nào bạn muốn, nhưng mỗi chuỗi chỉ xuất hiện một lần (không xuất bất kỳ bản sao nào).

Các trường hợp thử nghiệm

Input: .*, 1
Output: (trống string), , !, ", ..., },~

Đầu vào : w\w+, 3
Đầu ra : ww,www

Input: [abx-z][^ -}][\\], 3
Output: a~\, b~\, x~\, y~\,z~\

Input: ab*a|c[de]*, 3
Output: c, cd, ce, aa, cde, ced, cdd, cee,aba

Input: (foo)+(bar)?!?, 6
Output: foo, foo!, foofoo,foobar

Input: (a+|b*c)d, 4
Output: ad, cd, aad, bcd, aaad,bbcd

Đầu vào : p+cg, 4
Đầu ra : pcg,ppcg

Đầu vào : a{3}, 4
Đầu ra:a{3}

Người chiến thắng

Đây là , vì vậy mã ngắn nhất tính bằng byte sẽ giành chiến thắng!


Chúng tôi có được phép hỗ trợ các chuỗi thoát? Thì đây là chuyện nhỏ.
John Dvorak

3
Giải thích của |bạn làm cho rất ít ý nghĩa. Nó dường như không xử lý các nhóm lồng nhau hoặc a|b|c. Có gì sai khi sử dụng các giải thích tiêu chuẩn về mặt liên kết và xen kẽ mạnh mẽ như thế nào? (Và bạn không có lý do gì để không sử dụng hộp cát)
Peter Taylor

1
@PeterTaylor Thật ra, anh ta có một cái cớ: meta.codegolf.stackexchange.com/q/1305/9498
Justin

2
Đánh giá theo mẫu đề thi của bạn có phù hợp với toàn bộ chuỗi không? (Trái ngược với chuỗi con)
Martin Ender

3
@KyleKanos Đó là một vấn đề trong thế giới thực đáng xấu hổ không khiến bạn nghĩ rằng bạn nên học cách diễn đạt thông thường. : P Nhưng chúng không thể truy cập được như vẻ ngoài của chúng: thường xuyên- expresspress.info / tut.html
Martin Ender

Câu trả lời:


7

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

đầu ra:

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

Giải thích: đây là một triển khai regex trong sách giáo khoa. R là loại regex, với các hàm tạo A (thay thế), L (bằng chữ), T (sau đó) và E (trống / epsilon). 'Ngôi sao' thông thường không xuất hiện vì tôi đặt nội tuyến dưới dạng thay thế trong khi phân tích cú pháp (xem '%'). 'm' chạy mô phỏng. Trình phân tích cú pháp (bắt đầu tại 'rs = ....') chỉ là gốc đệ quy; 'k' phân tích phạm vi. Hàm '#' mở rộng phạm vi thành các thay thế.


7

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

Câu trả lời này có vẻ khá dài đối với một mã golf, nhưng có rất nhiều toán tử cần được xử lý và tôi biết mục đích của mỗi byte trong câu trả lời này là gì. Vì không có câu trả lời hiện có, tôi gửi đây là mục tiêu để người dùng khác đánh bại. Xem nếu bạn có thể làm cho một câu trả lời ngắn hơn :).

Hai hàm chính là fphân tích cú pháp regex bắt đầu từ iký tự thứ và dtạo ra các chuỗi khớp, sử dụng rcác biểu thức con mà chúng ta có thể đệ quy vào, 'a' mảng đại diện cho một phần của biểu thức con hiện tại chưa được xử lý, và một hậu tố chuỗi sđại diện cho một phần của chuỗi được tạo ra cho đến nay.

Ngoài ra kiểm tra đầu ra mẫukhai thác thử nghiệm .

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

Lưu ý rằng các tab trong giải pháp ban đầu đã được expanded. Để đếm số lượng ký tự trong sử dụng ban đầu unexpand < regex.py | wc.


9
Tôi chưa từng thấy trăn nhìn khủng khiếp.
user80551

Bạn không thể đổi def E(a,b):c=a[:];c.extend(b);return cthành E=lambda a,b:a[:].extend(b), ditto choA
user80551

Rõ ràng là không, vì .extend (b) không trả lại bất cứ điều gì.
gmatht

1
Đối với elif isinstance(e,str):, tôi tin rằng bạn có thể thay đổi mã bên trong thành: 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)')(lưu ý rằng đây #newlinelà một dòng mới) (nguồn: stackoverflow.com/a/103081/1896169 )
Justin

1
Nếu bạn có thể tìm thêm địa điểm để sử dụng thủ thuật thực thi, chúng tôi có thể dễ dàng thay đổi mã của bạn thành mã không thể đọc được :-)
Justin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.