我需要在写一个语法来解析游戏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'; 因此,我需要一个例子来说明如何在不产生错误的情况下对没有时间戳的行进行解析。
谢谢!
发布于 2010-05-12 22:37:25
没人会笑的。事实上,您在第一次尝试时就做得很好。当然,还有改进的空间!:)
首先要说明的是:您只能否定单个字符。因为您的NL规则可能由两个字符组成,所以您不能否定它。此外,当从解析器规则中进行否定时,您不会否定单个字符,而是否定词法分析器规则。这听起来可能有点困惑,所以让我用一个例子来说明一下。以组合(解析器和词法分析器)语法T为例
grammar T;
// parser rule
foo
: ~A
;
// lexer rules
A
: 'a'
;
B
: 'b'
;
C
: 'c'
;如您所见,我正在否定foo解析器规则中的A词法分析器规则。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的和TextLine的。
发布于 2010-05-12 23:06:13
试着尽可能地保持你的语法,下面是我是如何基于示例输入让它工作的。因为空格是从lexer传递给解析器的,所以我确实将解析器中的所有标记都转移到了实际的lexer规则中。主要的更改实际上只是添加了另一个行选项,然后尝试让它匹配您的测试数据,而不是实际的其他良好数据,我还假设应该丢弃空行,因为您可以根据规则来判断。这就是我所能做的:
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 : '/' | '\\';希望这对你有帮助,祝你好运。
https://stackoverflow.com/questions/2817891
复制相似问题