아마도 그것을 버리는 가장 중요한 것은 \s
수평 및 수직 공간 과 일치 하는 것입니다 . 가로 공간 만 일치 시키려면을 사용 \h
하고 세로 공간 만 일치 시키십시오 \v
.
한 가지 작은 권장 사항은 토큰에 줄 바꿈을 포함시키지 않는 것입니다. 또한 교대 연산자를 사용 할 수 있습니다 %
또는 %%
그들이 이런 종류의 작업을 처리하기 위해 설계된 것 같이 :
grammar Parser {
token TOP {
<headerRow> \n
<valueRow>+ %% \n
}
token headerRow { <.ws>* %% <header> }
token valueRow { <.ws>* %% <value> }
token header { \S+ }
token value { \S+ }
token ws { \h* }
}
이에 대한 결과 Parser.parse($dat)
는 다음과 같습니다.
「ID Name Email
1 test test@email.com
321 stan stan@nowhere.net
」
headerRow => 「ID Name Email」
header => 「ID」
header => 「Name」
header => 「Email」
valueRow => 「 1 test test@email.com」
value => 「1」
value => 「test」
value => 「test@email.com」
valueRow => 「 321 stan stan@nowhere.net」
value => 「321」
value => 「stan」
value => 「stan@nowhere.net」
valueRow => 「」
문법이 모든 것을 성공적으로 파싱했음을 보여줍니다. 그러나 질문의 두 번째 부분에 중점을 두어 변수에서 사용할 수 있기를 바랍니다. 그러기 위해서는이 프로젝트에 매우 간단한 액션 클래스를 제공해야합니다. 메소드가 문법의 메소드와 일치하는 클래스를 작성하십시오 (문자열 화 외에 특수 처리가 필요하지 않은 value
/ 와 같은 매우 단순한 클래스는 header
무시할 수 있음). 귀하의 처리를 처리하는 더 독창적이고 컴팩트 한 방법이 있지만, 나는 그림에 대한 초보적인 접근법을 사용합니다. 수업은 다음과 같습니다.
class ParserActions {
method headerRow ($/) { ... }
method valueRow ($/) { ... }
method TOP ($/) { ... }
}
각 메소드에는 ($/)
정규식 일치 변수 인 서명 이 있습니다. 이제 각 토큰에서 원하는 정보를 물어 보겠습니다. 헤더 행에서 각 헤더 값을 행으로 원합니다. 그래서:
method headerRow ($/) {
my @headers = $<header>.map: *.Str
make @headers;
}
그것에 한정 기호와 모든 토큰은으로 간주됩니다 Positional
우리는 또한 각 개별 헤더 경기에 액세스 할 수 있도록, $<header>[0]
, $<header>[1]
, 등을하지만 그이 일치하는 객체 우리가 신속하게 캐릭터 라인 화 있도록. 이 make
명령을 사용하면 다른 토큰이 우리가 만든이 특수 데이터에 액세스 할 수 있습니다.
$<value>
토큰이 우리의 관심사 이기 때문에 우리의 가치 행은 동일하게 보일 것 입니다.
method valueRow ($/) {
my @values = $<value>.map: *.Str
make @values;
}
마지막 방법에 도달하면 해시로 배열을 작성하려고합니다.
method TOP ($/) {
my @entries;
my @headers = $<headerRow>.made;
my @rows = $<valueRow>.map: *.made;
for @rows -> @values {
my %entry = flat @headers Z @values;
@entries.push: %entry;
}
make @entries;
}
여기에서 우리는 우리가 처리 된 물건에 액세스하는 방법을 볼 수 있습니다 headerRow()
와 valueRow()
당신은 사용 .made
방법. 여러 valueRows가 있기 때문에 각 made
값 을 얻으려면 맵을 작성해야합니다 (이것은 문법에 간단하게 문법을 작성 <header><data>
하고 데이터를 여러 행으로 무시하는 상황입니다). 충분히 간단하지는 않습니다).
이제 우리는 두 개의 배열에 헤더와 행을 가지고 있으므로 단순히 for
루프 에서 수행하는 해시 배열로 만드는 것 입니다. 는 flat @x Z @y
단지 요소를 intercolates, 해시 할당은 우리가 무엇을 의미하는지에 관해 않지만, 당신이 원하는 해시의 배열을 얻을 수있는 다른 방법이 있습니다.
완료되면, 당신은 make
그것을 made
파싱하고 파싱 에서 사용할 수 있습니다 :
say Parser.parse($dat, :actions(ParserActions)).made
-> [{Email => test@email.com, ID => 1, Name => test} {Email => stan@nowhere.net, ID => 321, Name => stan} {}]
이것을 다음과 같은 방법으로 감싸는 것이 일반적입니다.
sub parse-tsv($tsv) {
return Parser.parse($tsv, :actions(ParserActions)).made
}
그렇게하면 그냥 말할 수 있습니다
my @entries = parse-tsv($dat);
say @entries[0]<Name>; # test
say @entries[1]<Email>; # stan@nowhere.net
Nil
. 피드백이 진행되는 한 꽤 불합리합니다. 디버깅을 위해 쉼표를 다운로드 하지 않은 경우 다운로드 하거나 문법의 오류보고를 어떻게 개선 할 수 있습니까?를 참조하십시오 . . 당신은 가지고Nil
당신의 패턴을 되돌아 의미를 가정 사촌. 그것에 대한 내 대답을 참조하십시오. 역 추적을 피하는 것이 좋습니다. 이에 대한 @ user0721090601의 답변을 참조하십시오. 실용성과 속도에 대해서는 JJ의 답변을 참조하십시오. 또한, "일반적으로 X를 Raku와 구문 분석하고 싶습니다. 누구든지 도울 수 있습니까?" .