解析Gmail风格的高级搜索语法?

时间:2009-07-26 06:20:58

标签: perl search parsing context-free-grammar dbix-class

我想使用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. 不包括以连字符为前缀的标记。
  4. 这些元素也可以组合和嵌套:例如“{by:user5 - {tag:k by:user3}} etc”。

    我正在考虑编写一个无上下文语法来表示这些规则,然后将其解析为树。这不必要吗? (这是否可以使用简单的正则表达式?)

    建议使用哪些模块来解析无上下文语法?

    (最终这将用于使用DBIx :: Class生成数据库查询。)

4 个答案:

答案 0 :(得分:1)

正则表达式不会很好地嵌套事物(如括号)。当你获得正则表达式计数括号并正确捕获时,你可能有一个不错的CFG解析器。 CFG可以在逻辑上保证正确的解析,而使用正则表达式解决方案,你可以留下很多魔力。我不能推荐任何Perl CFG库,但是编写一个听起来非常流行。

答案 1 :(得分: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;
}

正则表达非常棒:)!

答案 2 :(得分:0)

YAPP可能会做你想要的。您可以使用它来生成然后使用LALR(1)Parsing Automaton。

答案 3 :(得分:0)

Parse::Recdescent可以为这种事情生成解析器。您可能需要一些解析器的经验才能有效地使用它。