Đặt hàng một phần các mẫu Regex


25

Với mục đích của thử thách này, chúng tôi nói rằng một mẫu regex khớp với một chuỗi nếu toàn bộ chuỗi được khớp với mẫu đó, không chỉ là một chuỗi con.

Với hai mẫu regex  Một  và  B , chúng ta nói rằng  A  được nhiều chuyên hơn  B   nếu mỗi chuỗi được kết hợp bởi  Một  cũng được kết hợp bởi  B   nhưng không phải là cách khác xung quanh. Chúng ta nói rằng  A  là tương đương với  B  nếu cả hai mô hình phù hợp chính xác cùng một tập các chuỗi. Nếu không có mẫu nào chuyên biệt hơn mẫu kia và chúng không tương đương, chúng tôi nói rằng  A  và  B  là không thể so sánh được .

Ví dụ, mô hình Hello, .*!là chuyên ngành hơn .*, .*!; các mẫu (Hello|Goodbye), World!Hello, World!|Goodbye, World!tương đương; và các mô hình Hello, .*!.*, World!là không thể so sánh được.

Mối quan hệ "chuyên biệt hơn" xác định một trật tự từng phần nghiêm ngặt trên tập các mẫu biểu thức chính quy. Đặc biệt, đối với tất cả các mẫu  A  và  B , chính xác một trong những điều sau đây là đúng:

  • A  chuyên hơn  B  ( A < B ).
  • B  chuyên biệt hơn  A  ( A > B ).
  • A  và  B  tương đương ( A = B ).
  • Một  và  B  không thể so sánh ( MộtB ).

Khi  A  và  B  không thể so sánh được, chúng ta có thể phân biệt rõ hơn giữa hai trường hợp:

  • Một  và  B  là rời nhau ( MộtB ), có nghĩa là không có chuỗi được kết hợp bởi cả hai.
  • Một  và  B  được giao nhau ( MộtB ), có nghĩa là một số chuỗi được kết hợp của cả hai.

Thử thách

Viết chương trình hoặc hàm lấy một cặp mẫu biểu thức chính và so sánh chúng bằng cách sử dụng thứ tự trên. Đó là, nếu hai mẫu là  A  và  B , chương trình nên xác định xem  A < B ,  A > B ,
A = B  hoặc  AB .

× 92% Tiền thưởng  Một phần thưởng bổ sung được đưa ra nếu, khi các mẫu không thể so sánh được, chương trình sẽ xác định xem chúng có giao nhau hay không khớp nhau.

Đầu vào và đầu ra

Chương trình nên chấp nhận hai mẫu regex, dưới dạng chuỗi, trong hương vị được xác định bên dưới. Bạn có thể đọc đầu vào thông qua STDIN , dòng lệnh , dưới dạng đối số hàm hoặc một phương thức tương đương . Bạn có thể cho rằng các mẫu là hợp lệ.

Chương trình sẽ tạo ra một trong bốn đầu ra riêng biệt (hoặc năm đầu ra riêng biệt nếu bạn sẽ nhận phần thưởng ở trên), tùy thuộc vào kết quả so sánh (đầu ra chính xác tùy thuộc vào bạn.) Bạn có thể viết đầu ra cho STDOUT , trả lại nó như là kết quả của hàm hoặc sử dụng một phương thức tương đương .

Hương vị Regex

Bạn có thể hỗ trợ bất kỳ tính năng regex nào bạn thích, nhưng bạn phải hỗ trợ các tính năng sau:

  • Thay thế với |.
  • Định lượng với *.
  • Phân nhóm với ().
  • Phù hợp với bất kỳ nhân vật (có thể loại trừ dòng mới) với ..
  • (Tùy chọn: × 80% Tiền thưởng)  Phù hợp với các lớp nhân vật đơn giản và bị phủ định với […][^…], tương ứng. Bạn không phải hỗ trợ bất kỳ lớp ký tự được xác định trước nào (ví dụ [:digit:]) nhưng bạn nên hỗ trợ phạm vi ký tự.
  • Nhân vật trốn thoát với \. Ít nhất nên có thể esacpe các ký tự đặc biệt (nghĩa là |*().[^-]\) và tốt nhất là các ký tự đặc biệt phổ biến trong các hương vị khác (ví dụ {}), nhưng hành vi khi thoát các ký tự không đặc biệt là không xác định. Cụ thể, bạn không phải hỗ trợ các chuỗi thoát đặc biệt, chẳng hạn như \ncho một dòng mới và những thứ tương tự. Một cách thực hiện có thể chỉ đơn giản là lấy ký tự theo \nghĩa đen.

Bạn có thể giả sử sự tồn tại của một ký tự đầu vào không thể phù hợp với bất kỳ nghĩa đen nào (nghĩa là nó chỉ có thể được khớp bởi .và các lớp ký tự bị phủ định.)

Quy tắc bổ sung

  • Bạn chỉ có thể sử dụng các thư viện regex hoặc chức năng regex dựng sẵn cho mục đích khớp và thay thế chuỗi.
  • Bạn có thể bỏ qua mọi vấn đề liên quan đến ngôn ngữ, chẳng hạn như quy tắc đối chiếu.
  • Để nói rõ ràng: chương trình của bạn phải chấm dứt. Nó sẽ thực thi trong một khoảng thời gian hợp lý với các mẫu điển hình (chắc chắn không quá một giờ, tốt nhất là ít hơn rất nhiều.)

Chấm điểm

Đây là mã golf. Điểm của bạn là sản phẩm của kích thước mã , tính bằng byte và bất kỳ phần thưởng nào . Điểm thấp nhất sẽ thắng.

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

Định dạng của các trường hợp thử nghiệm như sau:

<Test ID>
<Pattern A>
<Ordering>
<Pattern B>

<Test ID>
<Pattern A>
<Ordering>
<Pattern B>

...

Trường hợp <Test ID>định danh cho trường hợp thử nghiệm <Pattern A><Pattern B>là các mẫu biểu thức chính và <Ordering>là thứ tự giữa chúng và là một trong:

  • <: <Pattern A>là chuyên ngành hơn <Pattern B>.
  • >: <Pattern B>là chuyên ngành hơn <Pattern A>.
  • =: Các mẫu tương đương.
  • |: Các mô hình là không thể so sánh và rời rạc.
  • X: Các mô hình là không thể so sánh và giao nhau.

Giá trị đặc biệt <empty pattern>là viết tắt của mẫu trống.

A. Các mẫu cơ bản

B. Mẫu phức tạp

C. Các mẫu cơ bản với các lớp nhân vật

D. Các mẫu phức tạp với các lớp nhân vật

Chương trình kiểm tra

Đoạn mã sau có thể được sử dụng để so sánh các mẫu regex:

<style>#main {display: none;}#main[loaded] {display: inline;}.pattern_container {position: relative;}.pattern_underlay, .pattern {font: 12pt courier, monospace;overflow: hidden;white-space: pre;padding: 7px;box-sizing: border-box;}.pattern_underlay {background-color: #dddddd;color: #707070;border-radius: 4px;box-shadow: 0.5px 0.5px 2.5px #aaaaaa;}.pattern_underlay[error] {background-color: #ffccbb;}.pattern {position: absolute;left: 0px;top: 0px;background: none;border: none;width: 100%;height: 100%;resize: none;white-space: normal;}#ordering {min-width: 28pt;text-align: center;font-size: 16pt;}#status {padding: 5px;background-color: #fffdce;box-shadow: 1.5px 1.5px 3.5px #aaaaaa;font-size: 10pt;white-space: pre;display: none;}#status[error] {display: inline;background-color: #ffe8df;}#status[loading] {display: inline;}.inline_code {background-color: #dddddd;font: 12pt courier, monospace;padding: 2px;}.placeholder {visibility: hidden;}.error_text {background-color: #fffcb7};</style><span id="main"><table><tr><td><div class="pattern_container"><div class="pattern_underlay" id="pattern1_underlay"></div><textarea class="pattern" id="pattern1" oninput="compare()">Hello, .*!</textarea></div></td><td id="ordering"></td><td><div class="pattern_container"><div class="pattern_underlay" id="pattern2_underlay"></div><textarea class="pattern" id="pattern2" oninput="compare()">.*, .*!</textarea></div></td></tr></table><br></span><span id="status" loading>Loading...</span><script type='text/javascript'>var Module = {setStatus: function (status) {document.getElementById("status").innerHTML = status;if (status == "") {compare();document.getElementById("status").removeAttribute("loading");document.getElementById("main").setAttribute("loaded", 1);}}};function underlay_chars(str) {if (/^\n*$/.exec(str))return str.split("\n").map(function () { return '<span class="placeholder"> \n</span>'; });if (str.indexOf("\n") >= 0)str = str.replace(/\s*$/gm, function (m) { return m.replace(/[^\n]/g, "\0"); });return (str + "\n").split("").map(function (c) {if (c == "\0") return "·";else return '<span class="placeholder">' + c + '</span>';});}function underlay_str(str) {return underlay_chars(str).join("");}function str_to_array32(str) {a = [];for (c of str) {n = c.charCodeAt(0);a.push(n & 0xff, (n >> 8) & 0xff, (n >> 16) & 0xff, n >> 24);}a.push(0, 0, 0, 0);return a;}function compare() {try {for (e of ["pattern1_underlay", "pattern2_underlay", "status"])document.getElementById(e).removeAttribute("error");for (e of ["pattern1", "pattern2"])document.getElementById(e + "_underlay").innerHTML = underlay_str(document.getElementById(e).value);c = Module.ccall("regex_compare", "number", ["array", "array"], [str_to_array32(document.getElementById("pattern1").value),str_to_array32(document.getElementById("pattern2").value)]);if (c >= 0)document.getElementById("ordering").innerHTML = "∥≬<>="[c];else {i = Module.ccall("regex_error_index", "number", [], []);l = Module.ccall("regex_error_length", "number", [], []);e = document.getElementById("pattern" + -c + "_underlay");t = underlay_chars(document.getElementById("pattern" + -c).value);e.setAttribute("error", 1);e.innerHTML =t.slice(0, i).join("") +'<span class="error_text">' + t.slice(i, i + l).join("") + "</span>" +t.slice(i + l).join("");e.setAttribute("error", 1);throw "Pattern error: " + Module.ccall("regex_error", "string", [], []).replace(/`(.*?)'/g, '<span class="inline_code">$1</span>');}} catch (e) {document.getElementById("ordering").innerHTML = "??";document.getElementById("status").innerHTML = e;document.getElementById("status").setAttribute("error", 1);}}</script><script async type="text/javascript" src="https://gist.githack.com/anonymous/91f27d6746566c7b4e4c/raw/c563bf84a01c3a1c6e5f021369a3e730a2e74a1a/rpo.js"></script>


10
Ồ Bất kỳ câu trả lời nào được gửi tới đây đều nhận được +1 tự động từ tôi. Xác định xem hai ngôn ngữ chính thức là đẳng cấu là đủ khó. Xác định xem một trong những ngôn ngữ của một ngôn ngữ khác là một dự án CS đại học hoàn chỉnh. @ ___ @
COTO

Có bất kỳ hành vi được chỉ định cho các mẫu regex không hợp lệ?
Paul Guyot

@PaulGuyot số Bạn có thể giả sử các mẫu là hợp lệ.
Ell

1
Tôi tự hỏi - bạn đã viết chiến thắng cho chính mình (để xem nó khả thi như thế nào đối với một câu hỏi golf mã) hay không?
tự hào

1
@proudhaskeller tôi đã làm; Tôi đã viết đoạn kiểm tra. Đây là một thử thách khó khăn, và sẽ không có bất kỳ một chiếc tàu nào ở đây, nhưng nó có thể chơi được.
Ell

Câu trả lời:


10

Python 2, 522 byte * .92 = 480.24 537.28

Chỉnh sửa 2 : -60 byte

Chỉnh sửa : Đã thêm lời giải thích.

Định nghĩa là chức năng fmà phải mất hai chuỗi mẫu như các đối số và lợi nhuận '<', '=', '>', '|', hoặc 'X'. Cần ít hơn một phút để xử lý tất cả các trường hợp thử nghiệm.

Mã này bao gồm những điều sau đây, nhưng với \r, \n \tvà thoát hex (nhưng không phải \0) thay thế bằng các giá trị byte thực tế của họ.

#encoding=Latin
exec"""x\xda]RMo\xdb0\x0c\xbd\xe7Wx\'K\x96\x92\xc5mOR\xb8\xdf1@%|\x98%X\x80a\x19\x96\x02\x03n\xf2\xdfG:i;\xec$\x92z|\x8f_\x1b\x84%m~\xca\xbe\x1c\x0e\xbd\x0fU\x10Agi\x0e\x87\xea\n\x1f\xf9n{=\xea\0\x93\x08\xd2\xaez\xd0\x99\xcc,m\x07g\xbb\x80s\x9b\x08\xee\x8cRo"\xf3\x8bHy!-\x95\xd7\xa9\x8aS\xb50O5\xc3&\xb68\x0b\xe7\xb1\x19t\x92\x8a\x1d\xaf]\xc2f\x94\x92\x111T\xf3\xf1j\xba\x1b\x081r\xa2\x97\xea\xa5\x11\x03\x9bI\xca\xe6\xed\xe7\xab\xbd\xde`\xb6\x8b"\xd1\xc5\xf7\xd7?^l\xa7\xaeKK\xd7i\x91\x92\x8b\xaaE\x16\x8e\x9c\x12#3\x86\xe0"\xc6\xc9\x15\xfd\x86\xae\\\xde\xcc^\xa7\x94;,\xea\x94t\x08\x84\xa6J\x82\xee%\xb1\xe8\xacW\xb9\xb3\x14f\xd9\x84\xeb\x89\xe1\x8b\xd5\xa3r\xeb\xbf\x81D\rS\xf5\x8b/\xd7e\xaao\xf0\xeb\xf2\xbbv\xdd\xf1\x15\x1f\x93\xe4Aq\xff\x19\xc6\x98\x8b\xa8E\xad\xb2\xaae-m\x843\xc5\xd7!\x8e\xbe\xca.\x1a4\x01\xe8E;@-\xe4\xad9\xd5\xa7\x10\xa7\x9eg\xcea\x10\x83\x0e\xd2\r\x973\xb2o\xb8\xd7\x06\xc2\x0f\xa8\xdf\xdfk\x1b\x15\xb4v\x84H\xc9\xad]\xc1\x83C;\x03m\xc3\x16p\x1f\xe3\x1d\xbf\xa4\xe2\xbe\x8d\x1eX)\x1e\t\x9dv\xf3\xa9\xcd\xe8xGU\x9e\x0b\t\x97\xd6\x0c\x8c\xf2\nxa\xa9\x19u\xaf\xf2iN3\r\xd1\xae\x0f\xe3\x13\x0c@h\xb5W\xb0\xaad3\xef\t\x91s]R=~\xc3^Lv\xc7\x16\x15\xf4\xfb\xa7\x88ze_~B\x06\x80\x99\x03\x86\x7f\x0bY\x06U\xd2.\xeaV\x95\x87$\xd1\xce\xff\x8b\xbf\x9a\x99\xe0\x03u\xa1 =o0<n\xd0\xef]s`b\xb7\x98\x89\xael\xd2\x85\xceO:>\x80j\xfa\xdeb\x95\x95k\x91N\xbe\xfc'5\xac\xe7\xe8\x15""".decode('zip')

Câu lệnh trên khiến đoạn mã sau được thực thi:

z=frozenset
def f(f,s):
 u={s};d,l,f=n(f);w,h,s=n(s);_=0;r=[[z(f[0]),z(s[0])]]
 for e,o in r:
  p=z(zip([e]*h,o)+zip(e,[o]*l))
  if p-u:_|=((l in e)+2*(h in o))*4/3;u|=p;r+=[[reduce(z.__or__,(oo[i+1]for i in ii if ff[i]in[t,4][t<4:]),z())for ii,oo,ff in(e,f,d),(o,s,w)]for t in z([d[i]for i in e]+[w[i]for i in o])]
 return'|=><X'[_-3]
def n(s):
 s=list('('+s+')');i=0
 while s[i:]:f=s[i];h='()|*.'.find(f);s[i]=(h,f)[h<0];s[i:i+1]*=f!='\\';i+=1;l=i;h=1;w=e=[];p=[0];t=[{l}]
 while i:
  d=[i];i-=1;o=[i];f=s[i];t=[{i}]+t
  if f<1:h-=1;e+=zip(o*l,d+s.pop());w.pop()
  if f==1:h+=1;w=w+o;s+=[[]];e+=[o+d]
  if f==2:s[-1]+=d;e+=[(i,w[-1])]
  if h==p[-1]:e+=[t[-1:]+o,[i,1+t.pop()]];p.pop()
  if f==3:p+=[h];t+=o
 for f,o in e:
  for n in t:n|=(n,t[o])[f in n]
 return s+[1],l,t

Nếu mẫu mã thứ hai được lưu trữ trong chuỗi s, một cái gì đó tương tự như mẫu đầu tiên có thể được tạo bởi biểu thức '#encoding=Latin\nexec"""%s"""'%__import__('zlib').compress(s). Có thể cần phải sửa một số ký tự như byte rỗng hoặc dấu gạch chéo ngược. Mã được giải nén là gần 1000 800 byte, vì vậy có lẽ nó bị xáo trộn nhiều hơn so với đánh gôn ... nhưng ít nhất tôi đã xoay sở để đánh mã hóa một chút: từ Latin1đến Latin.

Giải trình

Chương trình hoạt động bằng cách sử dụng các chỉ số của chuỗi như một cách thô sơ để theo dõi các trạng thái phân tích chuỗi. Các nchức năng được xây dựng bảng chuyển tiếp. Đầu tiên, nó phân tích chuỗi và tìm tất cả các trường hợp của hai loại chuyển tiếp. Đầu tiên, có những chuyển đổi không liên quan đến việc thêm một chữ cái khác vào chuỗi. Ví dụ: nhảy từ *đầu đến đầu của một biểu thức được định lượng. Thứ hai, có sự chuyển tiếp của việc thêm một ký tự, chỉ đơn giản là di chuyển về phía trước bởi một chỉ mục. Sau đó, việc đóng chuyển tiếp của các chuyển tiếp không có ký tự được tính toán và chúng được thay thế cho các đích của các chuyển tiếp 1 ký tự. Vì vậy, nó trả về một ánh xạ của một chỉ mục và một ký tự cho một tập hợp các chỉ mục.

Hàm chính thực hiện BFS trên các chuỗi đầu vào có thể. Nó theo dõi một tập hợp tất cả các chỉ số có thể cho bất kỳ đoạn nào của chuỗi mà nó đang xem xét. Điều chúng tôi quan tâm trong việc tìm kiếm là các trạng thái được chấp nhận bởi cả hai biểu thức, hoặc bởi một và không phải là khác. Để chỉ ra rằng một regex được chấp nhận, chỉ cần tìm một đường chuyển tiếp có thể đến cuối mẫu. Nhưng để chỉ ra rằng một người bị từ chối, cần phải phân tích tất cả các con đường có thể. Do đó, để xác định xem các tập hợp trạng thái có thể có cho mẫu A và mẫu B đã được bao phủ bởi các trạng thái đã được phân tích trước đó chưa, các cặp trạng thái duy nhất trong một biểu thức chính quy và tập hợp tất cả các trạng thái có thể có trong trạng thái khác có được ghi lại hay không. Nếu không có cái mới, bạn có thể quay lại. Tất nhiên, nó cũng có thể, và ít nhân vật hơn,


Rất đẹp! Vượt qua tất cả các bài kiểm tra trong nhóm A và B (dường như không có lớp ký tự nào.) Tôi không thể làm cho phiên bản nén hoạt động, hoặc có cùng số byte. Dù bằng cách nào, bạn có thể yêu cầu x 0.92tiền thưởng khi bạn tính điểm của mình. Và, tất nhiên, một lời giải thích được chào đón!
Ell

4

Haskell, 560 553 618

có thể nhận được một số tiền thưởng được thực hiện trong tương lai.

Đây chưa phải là hoàn toàn golf.

import Data.List
c%j|'\\':h:s<-j=[s|c==h]|(a,b):_<-[(a,b)|x<-[0..length j],(a,'|':b)<-[splitAt x j],snd(k b)==[]]=c%a++c%b|'(':s<-j,(a,_:'*':b)<-k s=map(++j)(c%a)++c%b|'(':s<-j,(a,_:b)<-k s=map(++b)(c%a)|h:'*':s<-j=map(++j)(c%[h])++c%s
c%"."=[""|c>'\0']
c%s@[_]=c%('\\':s)
c%(a:b)=map(++b)(c%[a])
c%s=[""|c>'\0']
a&b=nub[(x,nub$b>>=(c%))|c<-[' '..'~'],x<-c%a]
g e(k@(a,l):r)|j<-a&l\\e=g(k:e)(j++r)
g e[]=e
a#b=or[all(null.('\0'%))m|(x,m)<-g[][(a,[b])],""<-'\0'%x]
a!b|a#b,b#a='x'|a#b='>'|b#a='<'|0<1='='
k"("=("","(")
k(c:s)|'('<-c,(x,y)<-k$tail b=('(':a++')':x,y)|')'<-c=("",')':s)|0<1=(c:a,b)where(a,b)=k s
k j=(j,j)

một lời giải thích lượn sóng của thuật toán:

reg!reg' trả về char yêu cầu, một trong "= <> x".

a#bđúng là không phải chuỗi nào acũng khớp b.

c%reglà danh sách các biểu thức chính quy regkhớp với c:smột trong các biểu thức chính trong kết quả khớp s. i về cơ bản là một phần phù hợp với regex. ngoại trừ nếu c'\0'. sau đó nó buộc regkhông nhận thêm bất kỳ đầu vào nào, trả về []nếu regphải lấy thêm đầu vào để khớp và [""]nếu không.

#hoạt động bằng cách tạo một danh sách hữu hạn của tất cả "trạng thái regex" có thể, hai biểu thức chính sẽ nằm sau một chuỗi tùy ý. sau đó để kiểm tra xem a<bchúng tôi có kiểm tra thời tiết hay không có "trạng thái regex" trong đó ahoàn toàn khớp nhưng bkhông khớp hoàn toàn.


Mát mẻ! Bạn rõ ràng đang đi đúng hướng. Tuy nhiên, ngay bây giờ nó thất bại kiểm tra B4.
Ell
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.