정규식 패턴의 부분 순서


25

이 문제를 해결하기 위해 전체 문자열이 하위 문자열이 아닌 패턴과 일치하는 경우 정규식 패턴이 문자열과 일치한다고 말합니다 .

을 감안할 때 두 정규식 패턴   와  B는 , 우리는 말할  A가  되어 보다 전문 보다  B   가 일치하는 모든 문자열이 경우  A는  도 일치한다  (B)   다른 방법으로 주위를하지만. 우리는 말할  A가  있습니다 상당 에  B  두 패턴이 정확히 문자열의 동일한 세트를 일치합니다. 어떤 패턴도 다른 패턴보다 더 전문화되거나 동일하지 않으면 A  와  B  는 비교할 수 없다고 말합니다  .

예를 들어 패턴 Hello, .*!.*, .*!; 패턴 (Hello|Goodbye), World!Hello, World!|Goodbye, World!동일하다; 패턴 Hello, .*!.*, World!비교할 수 없습니다.

"보다 전문화 된"관계는 정규식 패턴 세트에서 엄격한 부분 순서를 정의합니다. 특히, 모든 패턴  A  및  B 에 대해 정확히 다음 중 하나가 적용됩니다.

  • A  는 B 보다 더 전문화됩니다   ( A < B ).
  • B  는 A  ( A > B ) 보다 더 전문화되어  있습니다.
  • A  와  B  는 같습니다 ( A = B ).
  • A  와  B  는 비교할 수 없습니다 ( AB ).

때   와  B는  비교할 수없는, 우리는 더 이가지 경우를 구별 할 수 있습니다 :

  • A  와  B  는 분리 되어 있고 ( AB ), 두 문자열이 모두 일치하는 문자열이 없음을 의미합니다.
  • A  와  B  는 교차하고 있습니다 ( AB ). 이는 일부 문자열이 둘 다 일치 함을 의미합니다.

도전

정규식 패턴 쌍을 취하여 위의 순서를 사용하여 비교 하는 프로그램 이나 함수 를 작성하십시오 . 두 패턴 인 경우 즉,   및  B 프로그램을 결정할지 여부  < B ,  > B , = B  또는  ∥ B .

× 92 % 보너스  패턴을 비교할 수 없을 때 프로그램이 패턴이 교차하는지 또는 분리되어 있는지 판단하면 추가 보너스가 제공됩니다.

입력과 출력

프로그램은 아래 정의 된 특징에서 문자열로 두 개의 정규식 패턴을 수용해야합니다. STDIN , 명령 행을 통해 입력을 함수 인수 또는 동등한 메소드 로 읽을 수 있습니다 . 패턴이 유효하다고 가정 할 수 있습니다.

프로그램은 비교 결과 (정확한 출력이 사용자에게 달려 있음)에 따라 정확히 4 개의 고유 한 출력 중 하나 (또는 ​​위의 보너스를 받으려는 경우 5 개의 고유 한 출력)를 생성해야합니다. 출력을 STDOUT에 쓸 수 있습니다. 함수의 결과 로 반환 하거나 동등한 방법을 사용하십시오 .

정규식 맛

원하는 정규식 기능을 지원할 수 있지만 다음 기능을 지원 해야 합니다.

  • 교대|.
  • 정량화*.
  • 그룹화().
  • 일치하는 모든 문자 와 (아마도 제외 줄 바꿈) ..
  • (선택 사항 : × 80 % 보너스)  단순 및 부정 문자 클래스 를 각각 […]및로 일치 [^…]시킵니다. 사전 정의 된 문자 클래스 (예 :)를 지원할 필요는 없지만 [:digit:]문자 범위를 지원해야합니다.
  • 문자 이스케이프 와 함께 \. 적어도 특수 문자 (예 :) 를 이스케이프 할 수 있어야 |*().[^-]\하며 다른 특징 (예 :)에서 공통 특수 문자를 사용하는 것이 바람직 {}하지만 비 특수 문자를 이스케이프 처리하는 동작은 지정되어 있지 않습니다. 특히, \n개행 등과 같은 특수 이스케이프 시퀀스를 지원할 필요는 없습니다 . 가능한 구현은 단순히 문자 뒤에 \문자를 사용하는 것입니다.

어떤 리터럴과도 일치 할 수없는 입력 문자가 있다고 가정 할 수 있습니다 (즉, .문자 클래스와 만 일치 하고 무효화되는 문자 클래스 만 가능 ).

추가 규칙

  • 문자열 일치 및 교체 목적으로 만 정규식 라이브러리 또는 기본 제공 정규식 기능을 사용할 수 있습니다.
  • 데이터 정렬 규칙과 같은 로캘 관련 문제는 무시해도됩니다.
  • 명백한 사실을 밝히려면 프로그램을 종료해야합니다. 전형적인 패턴이 주어지면 합리적인 시간 내에 실행되어야합니다 (확실히 1 시간 이하, 바람직하게는 훨씬 적습니다).

채점

이것은 코드 골프입니다. 점수는 코드 크기 , 바이트 및 보너스 입니다 . 낮은 점수의 승리.

테스트 사례

테스트 케이스의 형식은 다음과 같습니다.

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

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

...

어디는 <Test ID>테스트 케이스에 대한 식별자, <Pattern A><Pattern B>정규식 패턴이며, <Ordering>그들 사이의 순서이며, 중 하나입니다 :

  • <: <Pattern A>보다 더 전문적입니다 <Pattern B>.
  • >: <Pattern B>보다 더 전문적입니다 <Pattern A>.
  • =: 패턴이 동일합니다.
  • |: 패턴이 비교할 수없고 분리되어 있습니다.
  • X: 패턴이 비교할 수없고 교차합니다.

특수 값 <empty pattern>은 빈 패턴을 나타냅니다.

A. 기본 패턴

B. 복잡한 패턴

C. 문자 클래스가있는 기본 패턴

D. 캐릭터 클래스가있는 복잡한 패턴

테스트 프로그램

다음 스 니펫을 사용하여 정규식 패턴을 비교할 수 있습니다.

<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
와우. 여기에 제출 된 모든 답변은 자동 +1을받습니다. 두 가지 공식 언어가 동형인지 여부를 결정하는 것은 어렵습니다. 하나가 다른 언어하위 언어 인지 확인하는 것은 완전한 학부 CS 프로젝트입니다. @ ___ @
COTO

유효하지 않은 정규식 패턴에 대해 지정된 동작이 있습니까?
Paul Guyot

@PaulGuyot 아니오. 패턴이 유효하다고 가정 할 수 있습니다.
Ell

1
궁금해-당신이 직접 작성 (코드 골프 질문에 대한 실현 가능성을 보려고) 했습니까?
자부심을 가진 haskeller

1
@proudhaskeller 내가 한; 테스트 스 니펫을 작성했습니다. 어려운 도전이며, 여기에는 한 개의 라이너가 없지만 골프는 가능합니다.
Ell December

답변:


10

파이썬 2, 522 바이트 * .92 = 480.24 537.28

편집 2 : -60 바이트

편집 : 설명이 추가되었습니다.

기능입니다 정의 f인수 및 반환으로 두 개의 패턴 문자열을 소요 '<', '=', '>','|' , 또는 'X'. 모든 테스트 사례를 처리하는 데 1 분 미만이 소요됩니다.

이 코드는 다음과 같이 구성되지만 함께 \r, \n \t및 헥사 이스케이프 (아니지만은 \0) 실제 바이트의 값으로 대체.

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

위의 문장으로 인해 다음 코드가 실행됩니다.

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

두 번째 코드 샘플이 문자열에 저장 s되면 첫 번째 코드 와 비슷한 것을 표현식으로 생성 할 수 있습니다 '#encoding=Latin\nexec"""%s"""'%__import__('zlib').compress(s). 널 바이트 또는 백 슬래시와 같은 일부 문자를 수정해야 할 수도 있습니다. 압축이 풀린 코드는 거의 1000 800 바이트이므로 아마도 골프보다 난독 화되지만 적어도 나는 인코딩을 조금만 골랐습니다.Latin1 습니다 Latin.

설명

이 프로그램은 문자열의 구문 분석 상태를 추적하기 위해 문자열 색인을 조잡한 방법으로 사용하여 작동합니다. 이 n함수는 전이 테이블을 빌드합니다. 먼저 문자열을 구문 분석하고 두 종류의 전이의 모든 인스턴스를 찾습니다. 먼저, 문자열에 다른 문자를 추가하지 않는 전환이 있습니다. 예를 들어* a에서 수량화 된 표현식의 시작으로 합니다. 둘째, 문자를 추가하는 전환이 있는데, 이는 단순히 하나의 색인만큼 앞으로 이동합니다. 그런 다음 문자 없음 전환의 전이 폐쇄가 계산되고 1 문자 전환의 대상으로 대체됩니다. 따라서 인덱스와 문자를 일련의 인덱스에 매핑합니다.

주요 기능은 가능한 입력 문자열에 대해 BFS를 수행합니다. 고려중인 문자열 조각에 대한 가능한 모든 색인 세트를 추적합니다. 우리가 찾는 것에 관심이있는 것은 두 정규식 모두에 의해 받아 들여 지거나 다른 하나에 의해 받아 들여지는 상태입니다. 정규식이 허용됨을 나타내려면 패턴 끝으로의 가능한 전환 경로를 하나만 찾으면됩니다. 그러나 하나가 거부되었음을 나타내려면 가능한 모든 경로를 분석해야합니다. 따라서, 패턴 A 및 패턴 B에 대한 가능한 상태 세트가 이미 분석 된 것에 의해 이미 커버되어 있는지를 결정하기 위해, 하나의 정규식에서 단일 상태의 쌍과 다른 하나에서 가능한 모든 상태의 세트가 기록된다. 새로운 것이 없다면 되돌아가도됩니다. 물론 가능하고 더 적은 캐릭터도 가능합니다.


아주 좋아요! 그룹 A와 B의 모든 테스트를 통과합니다 (문자 클래스가없는 것 같습니다.)하지만 압축 버전을 작동시킬 수 없거나 동일한 바이트 수를 얻을 수 없습니다. 어느 쪽이든 x 0.92점수를 계산할 때 보너스를 청구 할 수 있습니다 . 물론 설명도 환영합니다!
Ell December

4

하스켈, 560 553 (618)

앞으로 보너스를받을 수도 있습니다.

이것은 아직 완전히 골프되지 않았습니다.

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)

알고리즘에 대한 간단한 설명 :

reg!reg' "= <> x"중 하나 인 필수 문자를 반환합니다.

a#ba일치 하는 모든 문자열이에 의해 일치되는 것은 아닙니다 b.

c%reg출력의 정규 표현식 중 하나 reg와 일치 하는 정규식 목록입니다 . 나는 기본적으로 정규식과 부분적으로 일치합니다. 경우를 제외시켰다 이다 . 그런 다음 더 이상 입력을받지 못하게하고 더 많은 입력을 일치시켜야하는 경우 반환 합니다.c:ssc'\0'reg[]reg[""] .

#임의의 문자열 뒤에 두 정규 표현식이있을 수있는 모든 가능한 "정규 상태"의 유한 목록을 생성하여 작동합니다. 그런 다음 a<b날씨 를 확인하기 위해 "정규 상태" a가 완전히 일치하지만 b완전히 일치하지 않습니다.


시원한! 당신은 분명히 올바른 길을 가고 있습니다. 그러나 지금은 test에 실패합니다 B4.
Ell
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.