どのように私はパースTSVテキストに楽文法を定義することができますか?

littlebenlittle:

私はいくつかのTSVデータを持っています

ID     Name    Email
   1   test    [email protected]
 321   stan    [email protected]

私はハッシュのリストにこれを解析したいと思います

@entities[0]<Name> eq "test";
@entities[1]<Email> eq "[email protected]";

Iは、値列からヘッダ行を区切るために改行メタ文字を用いたトラブルを抱えています。私の文法定義:

use v6;

grammar Parser {
    token TOP       { <headerRow><valueRow>+ }
    token headerRow { [\s*<header>]+\n }
    token header    { \S+ }
    token valueRow  { [\s*<value>]+\n? }
    token value     { \S+ }
}

my $dat = q:to/EOF/;
ID     Name    Email
   1   test    [email protected]
 321   stan    [email protected]
EOF
say Parser.parse($dat);

しかし、これは戻っていますNil私は楽では正規表現についての基本的な何かを誤解と思います。

user0721090601:

おそらくそれを投げています主なものは、つまり\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    [email protected]
 321   stan    [email protected]
 headerRow => 「ID     Name    Email」
  header => 「ID」
  header => 「Name」
  header => 「Email」
 valueRow => 「   1   test    [email protected]
  value => 「1」
  value => 「test」
  value => 「[email protected]
 valueRow => 「 321   stan    [email protected]
  value => 「321」
  value => 「stan」
  value => 「[email protected]
 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>文法で、かつ複数の行としてデータをdefeineが、これはありますシンプルな十分な、それがあまりにも悪くはありません)。

今、私たちは2列にヘッダと行を持っていること、それは単にそれらを私たちがやるハッシュの配列、作るの問題だforループ。flat @x Z @y単に要素をintercolates、ハッシュ割り当ては、私たちが何を意味するかんが、あなたがしたいハッシュの配列を取得するための他の方法があります。

あなたが完了したら、あなただけのmakeそれは、それはで利用できるようになりますmadeパースの:

say Parser.parse($dat, :actions(ParserActions)).made
-> [{Email => [email protected], ID => 1, Name => test} {Email => [email protected], 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>;   # [email protected]

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=30264&siteId=1