【问题标题】:Help with parsing a log file (ANTLR3)帮助解析日志文件 (ANTLR3)
【发布时间】:2011-02-18 13:27:32
【问题描述】:

我需要一些指导来编写语法来解析游戏 Aion 的日志文件。我决定使用 Antlr3(因为它似乎是一个可以完成这项工作的工具,而且我认为学习使用它对我有好处)。但是,由于日志文件的结构不完全,我遇到了问题。

我需要解析的日志文件如下所示:

2010.04.27 22:32:22 : You changed the connection status to Online. 
2010.04.27 22:32:22 : You changed the group to the Solo state. 
2010.04.27 22:32:22 : You changed the group to the Solo state. 
2010.04.27 22:32:28 : Legion Message: www.xxxxxxxx.com (forum)



ventrillo: 19x.xxx.xxx.xxx

Port: 3712

Pass: xxxx (blabla) 

 4/27/2010 7:47 PM 
2010.04.27 22:32:28 : You have item(s) left to settle in the sales agency window.

如您所见,大多数行都以时间戳开头,但也有例外。我想在 Antlr3 中做的是编写一个解析器,它只使用以时间戳开头的行,而默默地丢弃其他行。

这是我到目前为止所写的(我是这些东西的初学者,所以请不要笑:D)

grammar Antlr;

options {
  language = Java;
}

logfile: line* EOF;

line : dataline | textline;

dataline: timestamp WS ':' WS text NL ;
textline: ~DIG text NL;

timestamp: four_dig '.' two_dig '.' two_dig WS two_dig ':' two_dig ':' two_dig ;

four_dig: DIG DIG DIG DIG;
two_dig: DIG DIG;

text: ~NL+;

/* Whitespace */ 
WS: (' ' | '\t')+;

/* New line goes to \r\n or EOF */
NL: '\r'? '\n' ;

/* Digits */
DIG : '0'..'9'; 

所以我需要的是一个示例,说明如何解析这个而不为没有时间戳的行生成错误。

谢谢!

【问题讨论】:

    标签: parsing antlr text-parsing antlr3


    【解决方案1】:

    没有人会笑。事实上,你第一次尝试就做得很好。当然,还有改进的余地! :)

    首先声明:你只能否定单个字符。由于您的 NL 规则可能包含两个字符,因此您不能否定它。此外,当从您的解析器规则中否定时,您不会否定单个字符,而是否定词法分析器规则。这听起来可能有点令人困惑,所以让我用一个例子来澄清一下。取组合(parser & lexer)语法T

    grammar T;
    
    // parser rule
    foo
      :  ~A
      ;
    
    // lexer rules
    A
      :  'a'
      ;
    
    B
      :  'b'
      ;
    
    C
      :  'c'
      ;
    

    如您所见,我在 foo parser-rule 中否定了 A lexer-rule。 foo 规则现在匹配除'a' 之外的任何字符,但它匹配除A 之外的任何词法分析器规则。换句话说,它只会匹配'b''c' 字符。

    另外,你不需要输入:

    options {
      language = Java;
    }
    

    在您的语法中:默认目标是 Java(当然,将其留在其中也无妨)。

    现在,在您的语法中,您已经可以在词法分析器语法中区分 data- 和 text-lines 了。这是一种可能的方法:

    logfile
      :  line+
      ;
    
    line
      :  dataline 
      |  textline
      ;
    
    dataline
      :  DataLine
      ;
    
    textline
      :  TextLine
      ;
    
    DataLine
      :  TwoDigits TwoDigits '.' TwoDigits '.' TwoDigits Space+ TwoDigits ':' TwoDigits ':' TwoDigits Space+ ':' TextLine
      ;
    
    TextLine
      :  ~('\r' | '\n')* (NewLine | EOF)
      ;
    
    fragment
    NewLine
      :  '\r'? '\n'
      |  '\r'
      ;
    
    fragment
    TwoDigits
      :  '0'..'9' '0'..'9'
      ;
    
    fragment
    Space
      :  ' ' 
      |  '\t'
      ;
    

    请注意,词法分析器规则中的fragment 部分意味着不会从这些规则中创建标记:它们仅用于其他词法分析器规则。所以词法分析器只会创建两种不同类型的标记:DataLine's 和 TextLine's。

    【讨论】:

    • 这似乎工作得很好,而且简单明了。 Ofcouse,我会改变一些东西来做我需要做的任何事情。谢谢!
    【解决方案2】:

    尽量保持语法接近,这是我如何根据示例输入使其工作的方法。因为空格是从词法分析器传递给解析器的,所以我确实将所有标记从解析器移到了实际的词法分析器规则中。主要的变化实际上只是添加了另一个行选项,然后试图让它匹配您的测试数据而不是实际的其他好的数据,我还假设应该丢弃一个空行,正如您可以通过规则判断的那样。所以这就是我能够开始工作的:

    logfile: line* EOF;
    
    //line : dataline | textline;
    line : dataline | textline | discardline;
    
    dataline: timestamp WS COLON WS text NL ;
    textline: ~DIG text NL;
    
    //"new"
    discardline: (WS)+ discardtext (text|DIG|PERIOD|COLON|SLASH|WS)* NL
        | (WS)* NL;
    discardtext: (two_dig| DIG) WS* SLASH;
    // two_dig SLASH four_dig;
    
    timestamp: four_dig PERIOD two_dig PERIOD two_dig WS two_dig COLON two_dig COLON two_dig ;
    
    four_dig: DIG DIG DIG DIG;
    two_dig: DIG DIG;
    
    //Following is very different
    text: CHAR (CHAR|DIG|PERIOD|COLON|SLASH|WS)*;
    
    /* Whitespace */ 
    WS: (' ' | '\t')+ ;
    
    /* New line goes to \r\n or EOF */
    NL: '\r'? '\n' ;
    
    /* Digits */
    DIG : '0'..'9'; 
    
    //new lexer rules
    CHAR : 'a'..'z'|'A'..'Z';
    PERIOD : '.';
    COLON : ':';
    SLASH : '/' | '\\';
    

    希望对你有所帮助,祝你好运。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-09
      • 1970-01-01
      • 2013-01-30
      • 2013-12-19
      相关资源
      最近更新 更多