使用Ragel解析用户代理

时间:2013-05-03 13:47:18

标签: regex ragel

我有来自apache的以下行(更改apache日志格式不是一个选项):

... referrer=- user_agent=JSON-RPC Client status=200 size=44 ...

我试图用Ragel解析它。除了user_agent之外,我将获取所有提取的字段。用户指南说强差--可确保第一台机器不包含第二台机器。就我而言,我希望匹配任何不包含" status="的内容,这将代表下一个字段。但是,我目前的定义(如下)似乎完全跳过user_agent;我仍然得到status并关注字段。我是否正确使用了强大的差异?

...
referrer   = ^space+             >mark %{ emit("referrer"); };
user_agent = any* -- ' status=' >mark %{ emit("user_agent"); };
status     = digit+              >mark %{ emit("status"); };
...

line = ( 
  ... 
  space "referrer=" 
  referrer 
  space "user_agent="
  user_agent
  space "status="
  status
  space "size="
  ...
);

2 个答案:

答案 0 :(得分:1)

我知道这个问题很老,但我刚刚进入Ragel,这可能对其他人有所帮助。

这里的问题是运营商优先级。操作操作符>%在强差异操作符--之前进行评估。用括号修复很容易:

user_agent = (any* -- ' status=') >mark %{ emit("user_agent"); };

我还会使用space而不是对空格进行硬编码,至少为了保持一致性:

user_agent = (any* -- (space 'status=')) >mark %{ emit("user_agent"); };

答案 1 :(得分:0)

您可以使用状态图表,尝试此状态机:

STATUS := digit+ ' ' @{ fnext SIZE; };
SIZE   := digit+;

USER_AGENT =
    start: (
        's'    -> s1 |
        [^s] @{ if (!ua_start) ua_start = p; }  -> start
    ),
    s1: (
        't'  -> s2 |
        [^t] -> start
    ),
    s2: (
        'a'  -> s3 |
        [^a] -> start
    ),
    s3: (
        't'  -> s4 |
        [^t] -> start
    ),
    s4: (
        'u'  -> s5 |
        [^u] -> start
    ),
    s5: (
        's'  -> s6 |
        [^s] -> start
    ),
    s6: (
        '='  @{ fnext STATUS; ua_stop = p - 7; } -> final |
        [^=] -> start
    )
    ;

main := "user_agent=" USER_AGENT ;

你可以在“ua_start”中获得用户代理 - > “ua_stop”,对于其他变量,我想你已经知道如何标记&得到角色。