정규식 컴파일


17

이 작업에서는 정규식을 읽고 입력 문자열이 해당 정규식에 의해 허용되는지 여부를 출력하는 다른 프로그램을 생성하는 프로그램을 작성해야합니다. 출력물은 제출물과 동일한 언어로 작성된 프로그램이어야합니다.

입력

입력은 다음 ABNF와 일치하는 정규식 r입니다 (초기 생산 규칙은 REGEX) :

REGEX       = *( STAR / GROUP / LITERAL / ALTERNATIVE )
STAR        = REGEX '*'
GROUP       = '(' REGEX ')'
LITERAL     = ALPHA / DIGIT
ALTERNATIVE = REGEX '|' REGEX

입력이이 문법과 일치하지 않으면 프로그램의 동작이 정의되지 않습니다.

해석

입력을 정규식으로 해석하십시오. 여기서 *Kleene-star ( 왼쪽 인수를 0 번 이상 반복 함 ) |는 대안 (이며 )그룹이며 연산자가 전혀 연결되어 있지 않습니다. 그룹화는 별보다 우선하고, 별은 연결보다 우선하고, 연결은 대안보다 우선합니다.

정규식이 전체 문자열과 일치하면 문자열이 허용 된다고 합니다.

산출

이 프로그램의 출력 문자열 읽어 제출과 같은 언어로 작성된 다른 프로그램 실행시에 구현 정의 된 방식으로, 여부를 출력 r은 받아 다음과이 종료됩니다. 수락 및 거부 된 프로그램에 대해 두 개의 고유 한 출력 만 있어야하지만 사용자 정의 방식으로 출력을 수행 할 수 있습니다.

출력 프로그램의 입력이 2 16 -1 바이트 보다 길지 않다고 가정 할 수 있습니다 .

제한 사항

제출물이나 제출물로 생성 된 프로그램은 내장 기능이나 라이브러리를 사용할 수 없습니다.

  • 정규식 일치
  • 정규식 변환
  • 정규식 컴파일
  • 문법에서 파서를 생성
  • 제출물이 사소한 방식으로 문제를 단순화

채점

제출 점수는 제출 한 문자 수입니다. 가장 낮은 점수를받은 제출이 승리합니다.

테스트 케이스

모든 테스트 케이스에는 정규식, 허용되는 문자열 세트, 거부 된 문자열 세트 및 C99의 예제 프로그램이 포함되어 있으며 (가상적인) C99 제출의 올바른 출력입니다.

(빈 정규식)

허용되는 문자열

  1. (빈 입력)

거부 된 문자열

  1. 바즈
  2. quux

프로그램 예

#include <stdio.h>

int main() {
    char input[65536];
    gets(input);

    return input[0] != 0;
}

(b|)(ab)*(a|)( a그리고 b교대로)

허용되는 문자열

  1. a
  2. ba
  3. abababababa
  4. abab

거부 된 문자열

  1. afba
  2. foo
  3. babba

예제 프로그램

#include <stdio.h>

int main() {
  char input[65536];
  int state = 0;

  for (;;) switch (state) {
    case 0: switch (getchar()) {
      case 'a': state = 1; break;
      case 'b': state = 2; break;
      case EOF: return 0;
      default:  return 1;
    } break;
    case 1: switch (getchar()) {
      case 'b': state = 2; break;
      case EOF: return 0;
      default:  return 1;
    } break;
    case 2: switch (getchar()) {
      case 'a': state = 1; break;
      case EOF: return 0;
      default:  return 1;
    } break;
}

(0|1(0|1)*)(|A(0|1)*1) (이진 부동 소수점 숫자)

허용되는 문자열

  1. 10110100
  2. 0
  3. 1A00001

거부 된 문자열

  1. 011
  2. 10A
  3. 1A00
  4. 100A010

1
나는 같은 프로그램을 가질 return (regex.match(stdin) is not null)수 없다고 생각합니다.
beary605

1
"출력은 입력과 같은 언어로 작성된 프로그램이어야합니다."라고 말하지만 입력은 정규식입니다. 제공하는 문법에는 리터럴 괄호를 정의하는 규칙 GROUP이 포함되어 있지 않습니다.
피터 테일러

@Peter 죄송합니다. 제출물과 동일한 언어를 쓰려고했습니다.
FUZxxl

네, 맞습니다. 섹션 참조 제한 : 제출하거나 제출에 의해 생성 된 모든 프로그램이 모두 기능이나 라이브러리 내장 사용할 수 일치하는 정규 표현식에 (...).
FUZxxl

두 번째 예제 프로그램이 잘못되었다고 생각합니다. 외부 스위치 주위에 루프가 없습니다.
Hasturkun

답변:


8

루비, 641 651 543 자

H=Hash.new{|h,k|[k]}
d=[[i=0,0,[]]]
o=[?(]
L="t,u,v=d.pop;q,r,s=d.pop;o.pop<?|&&(H[r]<<=t)||(H[q]<<=t;H[r]<<=u);d<<[q,u,s+v]"
gets.chop.chars.map{|c|c==?*&&(q,r,s=d.pop;H[r]|=[q,i+=1];d<<=[r,i,s];next)
eval(L)while/[|)]/=~c ?o[-1]>?(:o[-1]==?.
/[|(]/=~c&&d<<[i+=1,i,o<<c&&[]]||c!=?)&&d<<[i+=1,i+1,["s==#{o<<?.;i}&&c=='#{c}'&&#{i+=1}"]]||o[-1]=?.}
eval(L)while o.size>1
H.map{H.map{|k,v|v.map{|v|H[k]|=H[v]}}}
t,u,v=d[0]
$><<"s=#{H[t]};gets.chop.chars.map{|c|s=s.map{|s|#{v*'||'}}-[!0];#{H.map{|k,v|"s&[#{k}]!=[]&&s|=#{v}"}*?;}};p s&[#{u}]!=[]"

이 루비 버전은 정규 표현식 파서의 여러 가지 경우 때문에 상당히 길어졌습니다 (아마 다른 접근법을 시도해야 할 수도 있습니다). STDIN에서 정규 표현식을 예상하고 일치하는 해당 루비 코드를 STDOUT에 출력합니다.

프로그램은 NFA-ε에 대한 코드를 직접 생성 한 다음 매처에서 실행됩니다.

테스트 사례 1 : (추가 줄 바꿈 및 들여 쓰기가 포함 된 출력)

>>>

s=[0];
gets.chop.chars.map{|c|
  s=s.map{|s|}-[!0];
};
p s&[0]!=[]

테스트 사례 2 :

>>> (b|)(ab)*(a|)

s=[0, 1, 2, 4, 9, 5, 10, 6, 11, 12, 14];
gets.chop.chars.map{|c|
  s=s.map{|s|s==2&&c=='b'&&3||s==6&&c=='a'&&7||s==8&&c=='b'&&9||s==12&&c=='a'&&13}-[!0];
  s&[1]!=[]&&s|=[1, 2, 4, 9, 5, 10, 6, 11, 12, 14];
  s&[3]!=[]&&s|=[3, 4, 9, 5, 10, 6, 11, 12, 14];
  s&[0]!=[]&&s|=[0, 1, 2, 4, 9, 5, 10, 6, 11, 12, 14];
  s&[5]!=[]&&s|=[5, 6];
  s&[7]!=[]&&s|=[7, 8];
  s&[9]!=[]&&s|=[9, 5, 10, 6, 11, 12, 14];
  s&[4]!=[]&&s|=[4, 9, 5, 10, 6, 11, 12, 14];
  s&[11]!=[]&&s|=[11, 12, 14];
  s&[13]!=[]&&s|=[13, 14];
  s&[10]!=[]&&s|=[10, 11, 12, 14]
};
p s&[14]!=[]

또 다른 예:

>>> a|bc

s=[0, 1, 3, 4];
gets.chop.chars.map{|c|
  s=s.map{|s|s==1&&c=='a'&&2||s==4&&c=='b'&&5||s==6&&c=='c'&&7}-[!0];
  s&[0]!=[]&&s|=[0, 1, 3, 4];
  s&[3]!=[]&&s|=[3, 4];
  s&[5]!=[]&&s|=[5, 6];
  s&[2]!=[]&&s|=[2, 7]
};
p s&[7]!=[]

편집 : 의견에 언급 된 버그 PleaseStand 를 수정하는 전환을 추가했습니다 . 상태 초기화도 변경되었습니다.


011정규식 (0|1(0|1)*)(|A(0|1)*1)결과에 대한 입력 true-이어야합니다 false.
PleaseStand

@PleaseStand 고정. 내 편집 내용을 참조하십시오.
Howard

12

C, 627 자

이 프로그램은 첫 번째 명령 행 인수를 입력으로 처리하고 C 코드를 출력으로 생성합니다.

#define A(v) F[v]+strlen(F[v])
#define S sprintf
char*B="&&f%d(s)||f%d(s)",*J="&&f%d(s+%d)",*r,F[256][65536];h=2;e(f,n,o,R,C,O,t,g){for(C=O=f;*r;++r)switch(*r){case 40:r++;e(g=h++,C=h++,0,0);r[1]^42?t=g:(t=C,S(A(t),B,g,C=h++),r++);o=!S(A(O),J,t,o);O=C;break;case 41:goto L;case'|':S(A(C),J,n,o);o=!S(A(O=f),"||1");break;default:r[1]^42?S(A(C),"&&s[%d]==%d",o++,*r,O^f||R++):(o=!S(A(O),J,t=h++,o),O=C=h++,g=h++,S(A(g),"&&*s==%d&&f%d(s+1)",*r++,t),S(A(t),B,g,C));}L:S(A(C),J,n,o);}main(int c,char**v){r=v[1];for(e(1,!S(*F,"&&!*s"),0,0);h--;)printf("f%d(char*s){return 1%s;}",h,F[h]);puts("main(int c,char**v){exit(f1(v[1]));}");}

다음은 (0|1(0|1)*)(|A(0|1)*1)개행을 추가 한 결과입니다 .

f11(char*s){return 1&&s[0]==49&&f7(s+1);}
f10(char*s){return 1&&s[0]==48&&f9(s+1)||1&&s[0]==49&&f9(s+1);}
f9(char*s){return 1&&f10(s)||f11(s);}
f8(char*s){return 1&&f7(s+0)||1&&s[0]==65&&f9(s+1);}
f7(char*s){return 1&&f0(s+0);}
f6(char*s){return 1&&f2(s+0);}
f5(char*s){return 1&&s[0]==48&&f4(s+1)||1&&s[0]==49&&f4(s+1);}
f4(char*s){return 1&&f5(s)||f6(s);}
f3(char*s){return 1&&s[0]==48&&f2(s+1)||1&&s[0]==49&&f4(s+1);}
f2(char*s){return 1&&f8(s+0);}
f1(char*s){return 1&&f3(s+0);}
f0(char*s){return 1&&!*s;}
main(int c,char**v){exit(f1(v[1]));}

첫 번째 명령 행 인수로 유효한 입력을 제공하면 종료 상태 1을 리턴하고 그렇지 않으면 종료 상태 0을 리턴합니다.

$ ./regexcompiler '(0 | 1 (0 | 1) *) (| A (0 | 1) * 1)'> floatprog.c
$ gcc -o floatprog floatprog.c
floatprog.c : 'main'함수에서 :
floatprog.c : 1 : 519 : 경고 : 내장 함수 'exit'의 호환되지 않는 암시 적 선언 [기본적으로 활성화 됨]
$ ./floatprog '1A00001'&& echo invalid || echo 유효한
유효한
$ ./floatprog '100A010'&& echo invalid || 에코 유효
무효

명령 행 인수를 제공하지 않으면 프로그램 중 하나가 널 포인터를 역 참조하여 세그먼트 화 결함을 발생시킵니다. 충분히 긴 정규 표현식은이 제출의 버퍼를 오버 플로우하고 생성 된 프로그램에 대한 입력 크기는 스택의 크기에 의해 제한됩니다. 그러나 모든 테스트 사례가 작동합니다.

참고 e(g=h++,C=h++,0,0);소개하고 행동을 정의되지 않은. 예를 들어, 생성 된 프로그램이 컴파일되지 않으면 명령문을 h+=2;e(g=h-1,C=h-2,0,0);5 자보다 긴으로 대체 할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.