【问题标题】:Java - parsing text file - Scanner, Reader or something else?Java - 解析文本文件 - 扫描仪、阅读器或其他?
【发布时间】:2012-09-03 20:33:12
【问题描述】:

我想解析一个 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 给我单个字符(将其分隔符设置为空模式)来完成引用字符串的读取,因为我仍然认为它对于读取整数和浮点数很有用,但我不确定没有了。

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

基本上针对这个输入

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() // ]

等等。

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

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

【问题讨论】:

  • 我会使用正则表达式逐行解析该文件以提取标记。这对于语法检查同时很有用。
  • 我会使用 ANTLR 编写解析器。

标签: java parsing java.util.scanner


【解决方案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 debug 中试试看会发生什么。

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

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

【讨论】:

【解决方案2】:

使用类构造函数中的文件启动扫描程序。然后对于 nextWord 方法,这样做,

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-01
    • 2011-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多