유한 상태 오토마타에서 역 참조, 미리보기 및 미리보기를 시뮬레이션하는 방법은 무엇입니까?


26

정규 표현식을 가져와 구문 분석 트리를 생성하기 위해 간단한 정규 표현식 lexer 및 구문 분석기를 작성했습니다. 이 구문 분석 트리에서 비 결정적 유한 상태 오토 마톤을 작성하는 것은 기본 정규 표현식의 경우 비교적 간단합니다. 그러나 역 참조, lookaheads 및 lookbehinds를 시뮬레이션하는 방법에 대해 머리를 감싸는 것처럼 보이지 않습니다.

나는 보라색 드래곤 책에서 읽은 바로는 내가 내다을 시뮬레이션 할 수 있음을 이해 정규 표현식 곳 경기가 정규 표현에 일치하는 다음 경우에만하고있는 경우 일치 , 당신은 비 결정적 유한를 만들 가 바뀌는 상태 오토 마톤 . 결정 론적 유한 상태 오토 마톤을 생성 할 수 있습니까?r/srs/ε

부정적 예측과 예측을 시뮬레이션하는 것은 어떻습니까? 이 작업을 자세히 수행하는 방법을 설명하는 리소스에 연결하면 정말 감사하겠습니다.



답변:


21

우선, 역 참조는 비정규 언어를 설명 할 수 있기 때문에 유한 오토마타로 시뮬레이션 할 수 없습니다 . 예를 들어 컨텍스트가없는([ab]^*)\1 와 일치 합니다.{www{a,b}}

우리는 일치로 봐 미리와 모양 숨김 유한 오토마타의 세계에서 아무것도 특별 전체를 여기에 입력합니다. 따라서 "그냥 확인하지만 소비하지 말라"는 특별한 의미는 의미가 없습니다. 확인 및 소비 표현식을 연결 및 / 또는 교차하고 결과 오토마타를 사용하면됩니다. 아이디어는 입력을 "소비"하고 결과를 상태로 저장하는 동안 미리보기 또는 미리보기 표현식을 확인하는 것입니다.

정규 표현식을 구현할 때 자동 장치를 통해 입력을 실행하고 일치하는 시작 및 끝 인덱스를 가져 오려고합니다. 그것은 매우 다른 작업이므로, 유한 오토마타를위한 구성은 실제로 없습니다. 룩어 헤드 (look-ahead) 또는 룩-비하인드 (look-behind) 표현식이 소모되는 것처럼 오토 마톤을 구축하고 인덱스 저장 resp를 변경하십시오. 그에 따라보고.

예를 들어 살펴 보자. 암시 적으로 소비되는 "일괄"정규 표현식과 동시에 정규 표현식 검사를 실행하여 정규 표현식 의미를 모방 할 수 있습니다. look-behind 표현식의 오토 마톤이 최종 상태 인 상태에서만 가드 표현식의 오토 마톤을 입력 할 수 있습니다. 예를 들어, 정규 표현식 /(?=c)[ab]+/( 이 전체 알파벳 이라고 가정 )-정규식 -{ a ,{a,b,c}{a,b,c}c{a,b}+{a,b,c}

여기에 이미지 설명을 입력하십시오
[ 출처 ]

그리고 당신은해야 할 것입니다

  • (처음 또는 ) 를 입력 할 때마다 현재 색인을 로 저장 하고iq2q2
  • 때마다 에서 현재 색인 ( ) 으로 (최대) 일치를보고하십시오 .i1q2

오토 마톤의 왼쪽 부분이 각각 표준 오토마타 [abc]*c(반복 된) 오토마타의 병렬 오토 마톤 인 방법에 주목하십시오 .

예견도 비슷하게 처리 될 수 있습니다. "주"자동 장치를 입력 하면 색인 , 기본 자동 장치를 종료하고 미리 자동 제어 장치를 입력하고 미리 자동 제어 장치의 최종 결과에 도달 할 때만 에서 로 일치를보고 할 때 의 인덱스 를 기억 해야합니다. 상태.j 나는 jijij

비결정론은 이것에 내재되어 있다는 점에 유의하십시오. 기본 및 미리보기 / 비하인드 오토 마톤이 겹칠 수 있으므로 나중에 일치하는 것을보고하거나 역 추적하기 위해 이들 사이의 모든 전환을 저장해야합니다.


11

정규식 엔진 구현의 실질적인 문제에 대한 권위있는 참고 문헌은 Russ Cox의 일련의 블로그 게시물 입니다. 여기에 설명 된대로 역 참조는 언어를 비정규로 만들기 때문에 역 추적을 사용하여 구현됩니다 .

정규 표현식 패턴 일치 엔진의 많은 기능과 마찬가지로 LookAhead와 LookBehind는 문자열이 언어의 멤버인지 아닌지를 결정하는 패러다임에는 적합하지 않습니다. 정규 표현식 대신 우리는 일반적으로 더 큰 문자열 내에서 하위 문자열을 검색합니다. "일치"는 언어의 멤버 인 하위 문자열이며 반환 값은 더 큰 문자열 내에서 하위 문자열의 시작 및 끝 지점입니다.

lookaheads 및 lookbehinds의 요점은 비정규 언어를 일치시키는 기능을 도입하는 것이 아니라 엔진이 일치하는 하위 문자열의 시작 및 종료점을보고하는 위치를 조정하는 것입니다.

http://www.regular-expressions.info/lookaround.html 의 설명에 의존하고 있습니다. 이 기능을 지원하는 정규식 엔진 (Perl, TCL, Python, Ruby 등)은 모두 역 추적을 기반으로하는 것 같습니다 (즉, 일반 언어보다 훨씬 더 큰 언어 집합을 지원합니다). 그들은이 기능을 작업을 수행하기 위해 실제 유한 한 오토마타를 구성하려고하기보다는 비교적 "간단한"역 추적 확장으로 구현하는 것 같습니다.

긍정적 인 전망

긍정적 인 예측 의 구문 은 (?=regex) 입니다. 따라서 예를 들어 q(?=u)뒤에이 q있는 경우에만 일치하지만와 일치 u하지 않습니다 u. 나는 그들이 역 추적의 변형으로 이것을 구현한다고 상상한다. 긍정적 인 예측 전에 식에 대한 FSM을 작성하십시오. 일치하면 종료 위치를 기억하고 긍정적 인 예측 내부의 표현식을 나타내는 새 FSM을 시작하십시오. 일치하는 경우 "일치"가 있지만 양의 예측 예측 일치가 시작된 위치 바로 직전에 "종료"됩니다.

역 추적 없이는이 작업의 유일한 부분은 lookahead가 시작되는 입력 지점을 기억하고 일치하는 작업을 마친 후 입력 테이프를이 위치로 다시 이동해야한다는 것입니다.

부정적 예측

부정적 예측 의 구문 은 (?!regex) 입니다. 따라서 예를 들어 q(?!u)뒤에이 q없는 경우에만 일치 합니다 u. 이것은 q뒤에 다른 문자가 오거나 q문자열의 맨 끝에 있을 수 있습니다 . 이것은 lookahead 표현식에 대한 NFA를 생성 한 다음 NFA가 후속 문자열과 일치하지 않는 경우에만 성공함으로써 구현된다고 생각합니다.

역 추적에 의존하지 않고 수행하려면 lookahead 표현식의 NFA를 무효화하고 긍정적 인 lookahead를 처리하는 것과 동일한 방식으로 처리하십시오.

긍정적 인 전망

긍정적 인 lookbehind 의 구문 은 (?<=regex) 입니다. 따라서, 예를 들어, (?=q)u일치 u하지만이 앞에 경우에만, q하지만 일치하지 않습니다 q. 분명히 이것은 정규식 엔진이 실제로 백업하는 완벽한 해킹으로 구현 일치하는 문자와 시도를 정규식 사람들에 대해 문자. 이것은 정규 표현식 이 길이가 문자열과 만 일치해야 함을 의미합니다 .n nnnn

lookbehind 연산자 앞에 오는 정규식의 어떤 부분과 " regex로 끝나는 문자열"을 교차하여 역 추적없이이를 구현할 수 있습니다 . lookbehind 정규 표현식 은 현재 입력의 시작 부분보다 더 되돌아 볼 필요가 있기 때문에 까다로울 것입니다.

부정적인 전망

제외 lookbehind 의 구문 은 (?<!regex) 입니다. 따라서, 예를 들어, 앞에 오는 것이 아닌 경우에만 (?<!q)u일치 u합니다 q. 그것은 일치합니다 그래서 u에서 umbrellau에서 doubt가 아니라 u에서 quick. 다시 말하지만, 정규 표현식 의 길이를 계산하고 많은 문자를 백업하고 정규 표현식 과의 일치를 테스트 하지만 lookbehind가 일치하면 전체 일치가 실패하는 것으로 보입니다 .

정규식을 부정 하고 긍정적 인 전망을 위해하는 것과 똑같이함으로써 역 추적없이 이것을 구현할 수있을 것입니다.


5

적어도 역 참조의 경우에는 불가능합니다. 예를 들어 정규 표현식 (.*)\1은 정규적이 아닌 언어를 나타냅니다. 그 의미는이 언어를 인식 할 수있는 유한 오토 마톤 (결정적이든 아니든)을 만드는 것이 불가능하다는 것입니다. 이것을 공식적으로 증명 하려면 펌핑 보조를 사용할 수 있습니다 .


4

나는 이것을 직접 조사했으며 Alternating Finite Automaton을 사용하여 lookahead를 구현할 수 있어야합니다 . lookahead가 발생하면 lookahead와 나머지 표현식을 모두 비 결정적으로 실행하여 경로 가 모두 허용되는 경우에만 수락합니다. 명백한 구성이 캡처 그룹과 잘 작동하는지 확인하지는 않았지만 AFA를 합리적인 블로우 업을 통해 NFA로 변환 할 수 있으므로 DFA로 변환 할 수 있습니다.

고정 폭 룩백은 역 추적없이 완벽하게 가능해야합니다. n을 너비로 하자 . lookbehind가 시작된 NFA의 시점에서 시작하여 lookbehind로가는 모든 경로가 lookbehind 로만 들어가는 n 자 분량의 상태로 끝나도록 상태를 뒤로 살펴 봅니다. 그런 다음 해당 상태의 시작 부분에 미리보기를 추가하고 원하는 경우 하위 그래프를 AFA에서 NFA로 즉시 컴파일하십시오.

역 참조는 다른 사람들이 언급했듯이 규칙적이지 않으므로 유한 오토 마톤으로 구현할 수 없습니다. 실제로, 그들은 NP 완료입니다. 내가 작업하고있는 구현에서 빠른 예 / 아니오 일치가 가장 중요하므로 역 참조를 전혀 구현하지 않기로 선택했습니다.

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