1

Perl を使用して、Gmail が提供するものと同様の検索文字列を解析したいと考えています。入力例は、「tag:thing by:{user1 user2} {-tag:a by:user3}」です。のような木構造に入れたい

{and => [
    "tag:thing",
    {or => [
       "by:user1",
       "by:user2",
    ]},
    {or => [
       {not => "tag:a"},
       "by:user3",
    ]},
}

一般的な規則は次のとおりです。

  1. スペースで区切られたトークンは、デフォルトで AND 演算子になります。
  2. 中括弧内のトークンは代替オプション (OR) です。中かっこは、フィールド指定子の前後に配置できます。つまり、「by:{user1 user2}」と「{by:user1 by:user2}」は同等です。
  3. ハイフンで始まるトークンは除外されます。

これらの要素は、結合してネストすることもできます。たとえば、「{by:user5 -{tag:k by:user3}} など」です。

これらの規則を表す文脈自由文法を書き、それをツリーに解析することを考えています。これは不要ですか?(これは単純な正規表現を使用して可能ですか?)

文脈自由文法の解析に推奨されるモジュールは?

(最終的に、これは DBIx::Class でデータベースクエリを生成するために使用されます。)

4

4 に答える 4

1

正規表現は、ネストされたもの(括弧など)をうまく実行しません。正規表現のカウント括弧を取得して正しくキャプチャするまでに、おそらく適切なCFGパーサーを使用できます。CFGは論理的に正しい構文解析を保証できますが、正規表現ソリューションを使用すると、魔法に多くを任せることができます。Perl CFGライブラリをお勧めすることはできませんが、1つをコーディングすることは非常にカタルシスに聞こえます。

于 2009-07-26T06:59:41.837 に答える
0

クエリがツリー構造でない場合は、正規表現が代わりに機能します。

例えば:

my $search = "tag:thing by:{user1 user2} {-tag:a by:user3}"
my @tokens = split /(?![^{]*})\s+/, $search;
foreach (@tokens) {
    my $or = s/[{}]//g; # OR mode
    my ($default_field_specifier) = /(\w+):/;
}

クエリツリー構造になっている場合でも、正規表現を使用すると、再帰的な解析がより快適になります。

$_ = "by:{user1 z:{user2 3} } x {-tag:a by:user3} zz";
pos($_) = 0;
scan_query("");

sub scan_query {
    my $default_specifier = shift;
    while (/\G\s*((?:[-\w:]+)|(?={))({)?/gc) {
        scan_query($1), next if $2;
        my $query_token = $default_specifier . $1;
    }
    /\G\s*\}/gc;
}

正規表現は素晴らしいです:)!

于 2009-07-26T07:01:29.210 に答える
0

YAPPはあなたが望むことをするかもしれません。これを使用して、LALR(1) 解析オートマトンを生成してから使用できます。

于 2009-07-26T07:19:33.060 に答える
0

Parse::Recdescentは、この種のパーサーを生成できます。ただし、パーサーを効果的に使用するには、おそらくパーサーの経験が必要です。

于 2009-07-27T14:51:43.690 に答える