Regex Kalıplarının Kısmi Sırası


25

Bu zorluğun amacı doğrultusunda, tüm dize yalnızca bir alt dize değil, desenle eşleştirilirse , regex modelinin bir dizeyle eşleştiğini söylüyoruz .

Verilen iki regex desenleri  A  ve  B , biz demek  bir  edilir daha uzman daha  B   ile eşleşen her dize eğer  A  da örtüşmektedir  B   tersi değil. Biz söylemek  A  olan eşdeğer etmek  B  hem desenler tam olarak dizeleri aynı seti eşleşirse. Ne desen daha diğerinden daha uzmanlaşmış ne de eşdeğerdir edilirse, demek  A  ve  B  olan eşsiz .

Örneğin, model Hello, .*!fazla uzmanlaşmış .*, .*!; Desenler (Hello|Goodbye), World!ve Hello, World!|Goodbye, World!eşdeğerdir; ve desenler Hello, .*!ve .*, World!kıyaslanamaz.

"Daha uzmanlaşan" ilişkisi, regex kalıpları setinde katı bir kısmi düzen tanımlar. Özellikle, tüm A  ve  B kalıpları için  , tam olarak aşağıdakilerden biri doğrudur:

  • A  , B'den  ( A < B ) daha uzmandır  .
  • B  , A'dan  ( A > B ) daha uzmandır  .
  • A  ve  B  eşittir ( A = B ).
  • A  ve  B  karşılaştırılamaz ( AB ).

Ne zaman  bir  ve  B  kıyaslanamaz, biz daha iki dava arasında ayrım yapabilir:

  • A  ve  B  birbirinden ayrıdır ( AB ), bu da hiçbir dize tarafından eşleştirilmediği anlamına gelir.
  • A  ve  B  olan kesişen ( AB ) bazı dizeleri hem eşlenmişlerdir anlamına gelir.

Meydan okuma

Bir çift ​​regex paterni alan ve yukarıdaki sırayı kullanarak karşılaştıran bir program veya fonksiyon yazın . Yani, eğer iki kalıp  A  ve  B ise, program A < B ,  A > B ,
A = B  veya  AB olup olmadığını belirlemelidir  .

× 92% Bonus  Modeller karşılaştırılamaz olduğunda, program kesişen veya ayrık olup olmadıklarını belirlerse ek bir bonus verilir.

Giriş ve çıkış

Program, aşağıda tanımlanan tatta, dizge olarak iki regex şablonunu kabul etmelidir. Girdileri STDIN , komut satırı , işlev argümanları veya eşdeğer bir yöntem olarak okuyabilirsiniz . Modellerin geçerli olduğunu varsayabilirsiniz.

Program, karşılaştırmanın sonucuna bağlı olarak (kesin çıktılar size bağlıdır.) Tam olarak dört ayrı çıktıdan (ya da yukarıdaki ikramiyeye gidiyorsanız beş ayrı çıktıdan) birini üretmelidir . Çıktıyı STDOUT'a yazabilirsiniz. , işlevin sonucu olarak döndürün veya eşdeğer bir yöntem kullanın .

Regex Lezzet

Sen sever özellikleri ne olursa olsun regex destekleyebilir, ancak gerekir aşağıdaki olanları destekler:

  • Münavebe ile |.
  • Niceleme ile *.
  • Gruplandırma ile (ve ).
  • Herhangi bir karakterin eşleştirilmesi (muhtemelen yeni satırlar hariç) ..
  • (İsteğe bağlı: × 80% Bonus)  Basit ve olumsuz karakter sınıflarını sırasıyla […]ve ile eşleştirme [^…]. Önceden tanımlanmış herhangi bir karakter sınıfını (örn. [:digit:]) Desteklemeniz gerekmez, ancak karakter aralıklarını desteklemelisiniz.
  • Karakter kaçan ile \. En azından özel karakterleri (örn. |*().[^-]\) Ve tercihen diğer tatlardaki ortak özel karakterleri (örn. ) Çıkartabilmek mümkün olmalıdır, ancak özel {}olmayan karakterlerden kaçma davranışı belirtilmez. Özellikle, \nbir newline ve benzeri gibi özel kaçış dizilerini desteklemeniz gerekmez . Muhtemel bir uygulama basitçe onu izleyen karakteri almaktır \.

Herhangi bir değişmez tarafından eşleştirilemeyen bir giriş karakterinin varlığını varsayabilirsiniz (yani, yalnızca .karakter sınıfları ile eşleştirilebilir ve olumsuzlanabilir).

Ek Kurallar

  • Regex kitaplıklarını veya yerleşik regex işlevselliğini yalnızca dize eşleme ve değiştirme amacıyla kullanabilirsiniz.
  • Harmanlama kuralları gibi yerel ayarlarla ilgili sorunları görmezden gelebilirsiniz.
  • Açık bir şekilde ifade etmek için: programınız sonlandırılmalıdır. Tipik desenleri verilen makul bir süre içinde gerçekleştirmelidir (kesinlikle bir saatten fazla değil, tercihen çok daha az)

puanlama

Bu kod golfü. Puanınız ürün arasında kod boyutu bayt cinsinden, ve herhangi ikramiye . En düşük puan kazanır.

Test Kılıfları

Test senaryolarının formatı aşağıdaki gibidir:

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

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

...

Nerede <Test ID>test durumu için bir tanımlayıcı olup, <Pattern A>ve <Pattern B>düzenli ifade desenleri ve <Ordering>aralarındaki sıralamaya ve biridir:

  • <: <Pattern A>daha uzmanlaşmıştır <Pattern B>.
  • >: <Pattern B>daha uzmanlaşmıştır <Pattern A>.
  • =: Desenler eşdeğerdir.
  • |: Desenler karşılaştırılamaz ve ayrılmazdır.
  • X: Desenler karşılaştırılamaz ve kesişen.

Özel değer <empty pattern>boş kalıp anlamına gelir.

A. Temel kalıplar

B. Karmaşık desenler

C. Karakter sınıfları ile temel desenler

D. Karakter sınıfları ile karmaşık desenler

Test programı

Regex kalıplarını karşılaştırmak için aşağıdaki kod parçası kullanılabilir:

<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
Vay. Buna gönderilen cevaplar benden otomatik olarak +1 alır. İki biçimsel dilin izomorfik olup olmadığını belirlemek yeterince zordur. Birinin bir başkasının alt dili olup olmadığını belirlemek , tam bir lisans CS projesidir. @ ___ @
COTO,

Geçersiz regex kalıpları için belirlenmiş herhangi bir davranış var mı?
Paul Guyot

@PaulGuyot Hayır. Modellerin geçerli olduğunu varsayabilirsiniz.
Ell

1
Merak ediyorum - kendin kazandın (kod golf sorusu için ne kadar uygun olduğunu görmek için) yazdın mı?
Gurur haskeller

1
@ proudhaskeller Yaptım; Test pasajını yazdım. Bu zor bir mücadele ve burada birincisi olmayacak, ancak golf oynuyor.
Ell

Yanıtlar:


10

Python 2,252 bayt * .92 = 480.24 537.28

Düzenleme 2 : -60 bayt

Düzenleme : Açıklama eklendi.

Tanımlı fonksiyonudur fargümanları ve döner gibi iki desen dizileri alır '<', '=', '>', '|', ya da 'X'. Tüm test durumlarını işlemek için bir dakikadan daha az bir süre gereklidir.

Kod aşağıdakilerden oluşur, fakat \r, \n \tve altıgen kaçar (ancak \0) gerçek bit değerlerine döner.

#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')

Yukarıdaki ifade, aşağıdaki kodun yürütülmesine neden olur:

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

İkinci kod örneği dizede saklanırsa s, ifadeye benzer bir şey ilkine benzer şekilde üretilebilir '#encoding=Latin\nexec"""%s"""'%__import__('zlib').compress(s). Boş bayt veya ters eğik çizgi gibi bazı karakterleri düzeltmek gerekebilir. Çýkartýlan kod neredeyse olduğu 1000 daha golfed daha gizlenmiştir; belki 800 bayt ... ama en azından biraz kodlayan golf başardı: den Latin1üzere Latin.

açıklama

Program, bir dize ayrıştırma durumlarını izlemek için dizenin dizinlerini kaba bir yol olarak kullanarak çalışır. nFonksiyon geçiş tabloları oluşturur. İlk önce dizgeyi ayrıştırır ve iki tür geçişin tüm örneklerini bulur. İlk olarak, dizeye başka bir harf eklemeyi gerektirmeyen geçişler var. Örneğin, a'dan *nicelenmiş bir ifadenin başlangıcına atlama . İkincisi, bir karakter ekleme geçişleri var, bunlar sadece bir indeks ile ilerliyor. Sonra, karaktersiz geçişlerin geçişli kapatılması hesaplanır ve bunlar 1 karakterli geçişlerin varış yerleri için değiştirilir. Böylece bir indeksin eşlemesini ve bir indeks kümesine bir karakter döndürür.

Ana işlev, olası giriş dizeleri üzerinden bir BFS yapar. Ne düşündüğü bir dize parçası için mümkün olan tüm indeksleri izler. Bulmak istediğimiz şey, her iki regex tarafından ya da biri tarafından değil, biri tarafından kabul edilen devletlerdir. Bir regex'in kabul edildiğini göstermek için, desenin sonuna kadar yalnızca olası bir geçiş yolu bulmak gerekir. Ancak birinin reddedildiğini göstermek için, olası tüm yolları analiz etmek gerekir. Bu nedenle, A deseni ve B deseni için olası durum kümelerinin daha önce analiz edilenlerle kapsanıp kaplanmadığını belirlemek için, bir regex'te tek bir durumun çiftleri ve diğerinde tüm olası durumların kümesi kaydedilmiştir. Yenileri yoksa, geri dönme tamamdır. Tabii ki, mümkün ve daha az karakter olacaktı


Çok hoş! A ve B gruplarındaki tüm testleri geçiyor (karakter sınıfları yok, öyle görünüyor.) Sıkıştırılmış sürümün çalışmasına rağmen aynı bayt sayısını alamıyorum. Her iki durumda da x 0.92, puanınızı hesaplarken bonusu talep edebilirsiniz . Ve tabii ki, bir açıklama açığız!
Ell

4

Haskell, 560 553 618

Gelecekte yapılan bazı ikramiye alabilirsiniz.

Bu henüz tam olarak golf değil.

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)

algoritmanın el dalgalı bir açıklaması:

reg!reg' "= <> x" ifadesinden istenen karakteri döndürür.

a#btrue Eğer aeşleşen her dize de uymuyorsa doğrudur b.

c%regçıktı eşleşmelerindeki regexps'lerden birini regeşleştiren normal ifadelerin bir listesidir . i, temel olarak kısmen regex ile eşleşir. eğer hariç olduğunu . o zaman daha fazla girdi almaya zorlar , eşleşmek için daha fazla girdi almak zorunda kalırsa geri döner .c:ssc'\0'reg[]reg[""]

#iki regexps isteğe bağlı bir dize sonra olacak tüm olası "regex-state" bir sınırlı listesi üreterek çalışır. Daha sonra a<bhava durumunu kontrol edip etmediğimizi kontrol etmek için a, tamamen eşleştirilen ancak eşleşmeyen bir "regex-state" var b.


Güzel! Belli ki doğru yoldasın. Ancak, şu anda test başarısız olur B4.
Ell
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.