3

我想解析一个 UTF8 编码的文本文件,它可能包含这样的内容:

int 1
text " some text with \" and \\ "
int list[-45,54, 435 ,-65]
float list [ 4.0, 5.2,-5.2342e+4]

列表中的数字用逗号分隔。此处允许在任何数字和任何符号(如逗号和括号)之间使用空格,但不需要空格。对于单词和符号也是如此,例如list[

我通过强制 Scanner 给我单个字符(将其分隔符设置为空模式)来完成引用字符串的读取,因为我仍然认为它对于读取整数和浮点数很有用,但我不确定了。

Scanner 总是获取一个完整的令牌,然后尝试匹配它。我需要的是尝试尽可能多(或尽可能少地)匹配,而不考虑分隔符。

基本上对于这个输入

int list[-45,54, 435 ,-65]

我希望能够打电话并得到这个

s.nextWord()   // int 
s.nextWord()   // list
s.nextSymbol() // [
s.nextInt()    // -45
s.nextSymbol() // ,
s.nextInt()    // 54
s.nextSymbol() // ,
s.nextInt()    // 435
s.nextSymbol() // ,
s.nextInt()    // -65
s.nextSymbol() // ]

等等。

或者,如果它本身无法解析双精度数和其他类型,则至少有一个采用正则表达式的方法,返回与其匹配的最大字符串(或错误)并将流位置设置为紧随其匹配的位置。

扫描仪可以以某种方式用于此目的吗?还是有其他方法?我觉得这一定是一件很常见的事情,但我似乎无法找到合适的工具。

4

2 回答 2

1

我不是 ANTLR 专家,但这个ANTLR语法能够解析您的代码:

grammar Expressions;

expressions 
    :   expression+ EOF
    ;

expression 
    :   intExpression
    |   intListExpression
    |   floatExpression
    |   floatListExpression
    |   textExpression
    |   textListExpression
    ;

intExpression        :  intType INT;
intListExpression    :  intType listType '[' ( INT (',' INT)* )? ']';
floatExpression      :  floatType FLOAT;
floatListExpression  :  floatType listType '[' ( (INT|FLOAT) (',' (INT|FLOAT))* )? ']';
textExpression       :  textType STRING;
textListExpression   :  textType listType '[' ( STRING (',' STRING)* )? ']';

intType   :  'int';
floatType :  'float';
textType  :  'text';
listType  :  'list';

INT :   '0'..'9'+
    ;

FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
    |   '.' ('0'..'9')+ EXPONENT?
    |   ('0'..'9')+ EXPONENT
    ;

STRING
    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
    ;

fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;

fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;

fragment
OCTAL_ESC
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;

fragment
UNICODE_ESC
    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;

当然你需要改进它,但我认为使用这种结构很容易在解析器中插入代码来做你想做的事情(一种令牌流)。在ANTLRWorks调试中尝试一下,看看会发生什么。

对于您的输入,这是解析树:

OP 输入的解析树

编辑:我将其更改为支持空列表。

于 2012-09-03T21:38:47.043 回答
0

使用类构造函数中的文件启动扫描程序。然后对于 nextWord 方法,执行此操作,

public static nextWord(){
return(sc.findInLine("\\w+"));
}

您可以使用上面的示例以及 Scanner 类的 findInLine 方法并更改正则表达式模式来派生其他方法的代码。

于 2012-09-03T21:15:23.320 回答