2017-12-01 2 views
3

실제로 연습 할 때 쉘 명령의 출력 인 표준 텍스트를 구문 분석하려고합니다.Perl6 구문 분석 파일

pool: thisPool 
state: ONLINE 
status: Some supported features are not enabled on the pool. The pool can 
    still be used, but some features are unavailable. 
action: Enable all features using 'zpool upgrade'. Once this is done, 
    the pool may no longer be accessible by software that does not support 
    the features. See zpool-features(5) for details. 
    scan: none requested 
config: 

    NAME            STATE  READ WRITE CKSUM 
    homePool           ONLINE  0  0  0 
     mirror-0           ONLINE  0  0  0 
     ata-WDC_WD5000AZLX-00CL5A0_WD-WCC3F7NUE93C  ONLINE  0  0  0 
     ata-WDC_WD5000AZLX-00CL5A0_WD-WCC3F7RE2A4F  ONLINE  0  0  0 
    cache 
     ata-KINGSTON_SV300S37A60G_50026B7261025D7E-part3 ONLINE  0  0  0 

errors: No known data errors 

은 내가 Perl6 문법을 사용하려면 내가 별도의 토큰 또는 정규식에서 각 필드를 캡처 할. 그래서, 나는 다음과 같은 문법을했다 :

grammar zpool { 
     regex TOP { \s+ [ <keyword> <collection> ]+ } 
     token keyword { "pool: " | "state: " | "status: " | "action: " | "scan: " | "config: " | "errors: " } 
     regex collection { [<:!keyword>]* } 
} 

내 생각은 정규식 후 다음 키워드 때까지 모든 데이터를 수집하기 시작, 키워드를 발견 한 것입니다. 그러나 매번 나는 "풀 :"-> 모든 나머지 텍스트를 얻습니다. 나는 그 다음은 키워드를 발견하면 문자를 먹는 중지에 도착하는 방법을 모른다

keyword => 「pool: 」 
collection => 「homePool 
state: ONLINE 
status: Some supported features are not enabled on the pool. The pool can 
    still be used, but some features are unavailable. 
action: Enable all features using 'zpool upgrade'. Once this is done, 
    the pool may no longer be accessible by software that does not support 
    the features. See zpool-features(5) for details. 
    scan: none requested 
config: 

    NAME            STATE  READ WRITE CKSUM 
    homePool           ONLINE  0  0  0 
     mirror-0           ONLINE  0  0  0 
     ata-WDC_WD5000AZLX-00CL5A0_WD-WCC3F7NUE93C  ONLINE  0  0  0 
     ata-WDC_WD5000AZLX-00CL5A0_WD-WCC3F7RE2A4F  ONLINE  0  0  0 
    cache 
     ata-KINGSTON_SV300S37A60G_50026B7261025D7E-part3 ONLINE  0  0  0 

errors: No known data errors 
」 

은 또 다른 키워드로 취급합니다.

답변

5

당신은 <!keyword> 대신 <:!keyword>를 작성한 1

문제. 그것은 당신이 원하는 것이 아닙니다. :을 삭제해야합니다. 이 경우

P6 정규식 matches a single character with the specified Unicode property<:foo> 구문은 속성 :foo 차례로 :foo(True)을 의미한다.

그리고 <:!keyword>은 유니 코드 속성 :keyword(False) 인 단일 문자와 일치합니다.

그러나 유니 코드 속성 :keyword은 없습니다.

음수 어설 션은 항상 true이며 항상 매번 입력의 단일 문자와 일치합니다.

그래서 패턴은 다른 텍스트를 통해 전달됩니다. 당신은 문제 하나를 해결하면

문제 2

, 두 번째 문제가 발생합니다.

<:!keyword>은 유니 코드 속성 :keyword(False)과 일치합니다. 일치 할 때마다 자동으로 입력 (단일 문자)을 실행합니다.

대조적으로 <!keyword>은 일치 할 경우 입력을 소비하지 않습니다. 입력 패턴을 사용하는 패턴을 입력해야합니다.


그 두 가지 문제를 해결 한 후에 당신은 당신이 예상 출력의 종류를 얻을 수 있습니다. (입력 파일 예에서 의 config:에 공백이 오지 않기 때문에 config 키워드가 작동하지 않는다는 다음 문제가 있습니다.) 몇 클린 업에

그래서

: 나는 token 선언으로 모든 패턴을 전환했습니다

my @keywords = <pool state status action scan config errors> ; 

say grammar zpool { 
    token TOP  { \s+ [ <keyword> <collection> ]* } 
    token keyword { @keywords ': ' } 
    token collection { [ <!keyword> . ]* } 
} 

. 일반적으로 항상 token을 사용하십시오. 을 알고있는 경우을 알고 있어야합니다. (regex는 역 추적을 할 수 있습니다. 그 수 극적으로 천천히 일을 당신이 조심하지 않으면. rule 규칙 상당한 공백 을 수 있습니다.) 내가 배열에 키워드를 추출했습니다

. @keywords@keywords[0] | @keywords[1] | ...을 의미합니다.

나는 마지막 패턴 <!keyword>.를 추가했습니다 (그렇지 않으면 <!foo> 어떤 입력을 소비하지 않는 주어진 발생할 수있는 무한 루프를 방지하기 위해, 입력의 캐릭터의 가치를 소비합니다).

만약 당신이 그들을 보지 못했다면, available grammar debugging options은 당신의 친구입니다.

제 H

3

내가 지금하고 좋은 문법을 사랑하는,이 split에 전화로 해결하는 것이 훨씬 쉽다만큼 :

my $input = q:to/EOF/; 
    pool: thisPool 
state: ONLINE 
status: Some supported features are not enabled on the pool. The pool can 
    still be used, but some features are unavailable. 
action: Enable all features using 'zpool upgrade'. Once this is done, 
    the pool may no longer be accessible by software that does not support 
    the features. See zpool-features(5) for details. 
    scan: none requested 
config: 

    NAME            STATE  READ WRITE CKSUM 
    homePool           ONLINE  0  0  0 
     mirror-0           ONLINE  0  0  0 
     ata-WDC_WD5000AZLX-00CL5A0_WD-WCC3F7NUE93C  ONLINE  0  0  0 
     ata-WDC_WD5000AZLX-00CL5A0_WD-WCC3F7RE2A4F  ONLINE  0  0  0 
    cache 
     ata-KINGSTON_SV300S37A60G_50026B7261025D7E-part3 ONLINE  0  0  0 

errors: No known data errors 
EOF 

my @delimiter = <pool state status action scan config errors>; 
my %fields; 
for $input.split(/ ^^ \h* (@delimiter) ':' \h*/, :v)[1..*] -> $key, $value { 
    %fields{ $key[0] } = $value.trim; 
} 

say %fields.perl; 

이 알려진 키에 분할 폐기에 의해 작동 첫 번째 요소 (입력이 값이 아닌 키로 시작한다는 것을 알고 있으므로), 그리고 lockstep에서 키와 값을 반복합니다.

이제는 문법을 묻기 때문에 split 호출을 .+? (가능한 한 짧은 문자열)로 각 값을 바꾸면 순수 정규식으로 쉽게 바꿀 수 있습니다.

my @delimiter = <pool state status action scan config errors>; 
grammar ZPool { 
    regex key  { @delimiter    } 
    regex keychunk { ^^ \h* <key> ':'  } 
    regex value { .*?     } 
    regex chunks { <keychunk> \h* <value> } 
    regex TOP  { <chunks>+    } 
} 

우리는 중첩 된 매치 트리에서 결과를 추출하는 힘든 일을하거나, 대신 상태 액션 객체와 속임수 수 :

class ZPool::Actions { 
    has $!last-key; 
    has %.contents; 
    method key($m) { $!last-key = $m.Str    } 
    method value($m) { %!contents{ $!last-key } = $m.trim } 
} 

그리고 지금의 그것에게 좀 더 구조를 제공 할 수

그리고 그것을 사용 :

my $actions = ZPool::Actions.new; 
ZPool.parse($input, :$actions); 
say $actions.contents.perl; 

key과을은 역 추적 할 필요가 없으므로 regex에서 token으로 변경할 수 있습니다.

물론 .+?과 역 추적을 사용하면 부정 행위로 간주 될 수 있으므로 정규 표현식 안의 부정적 미리보기로 언급 한 raiph 트릭을 사용할 수 있습니다.