おそらくそれを捨てている主なものは、\s
水平方向と垂直方向のスペースを一致させることです。水平方向のスペースだけを一致させるにはを使用し\h
、垂直方向のスペースだけを一致させるにはを使用します\v
。
私が行う1つの小さな推奨事項は、トークンに改行を含めないことです。また、これらのタイプの作業を処理するように設計されているため、代替演算子%
またはを使用することもでき%%
ます。
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 => 「」
これは、文法がすべてを正常に解析したことを示しています。ただし、変数の中で利用できるようにしたいという質問の2番目の部分に焦点を当てましょう。そのためには、このプロジェクトで非常に簡単なアクションクラスを指定する必要があります。メソッドが文法のメソッドと一致するクラスを作成するだけです(ただし、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>
に持つように文法を記述し、データを複数の行として定義する傾向がある状況ですが、これは十分にシンプルで、それほど悪くはありません)。
ヘッダーと行が2つの配列になっているので、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
。フィードバックに関してはかなり不毛ですよね?デバッグするには、まだ行っていない場合は、commideをダウンロードしてください。または、「文法のエラー報告をどのように改善できるか」を参照してください。。あなたはNil
、パターンがバックトラックのセマンティクスを想定していることを知った それについての私の答えを見てください。バックトラックを避けることをお勧めします。これについては@ user0721090601の回答を参照してください。実用性とスピードについては、JJの回答をご覧ください。また、「RakuでXを解析したいのですが、だれでも手伝ってくれますか?」に対する一般的な回答です。。