执行摘要:在Java的\R
中使用Scanner
(或其他正则表达式模式)是否有任何警告/已知问题(特别是关于内部缓冲区的边界条件)?
细节:由于我想在潜在的多平台输入文件上进行一些多线模式匹配,我使用了\R
的模式,根据Pattern
javadoc,它是:
任何Unicode换行符序列都等同于
\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]
无论如何,我注意到在我的一个测试文件中,应该解析一个十六进制转储块的循环被缩短了。经过一些调试后,我注意到它结束的那一行是Scanner内部缓冲区的结束。
这是我写的一个测试程序来模拟这种情况:
public static void main(String[] args) throws IOException {
testString(1);
testString(1022);
}
private static void testString(int prefixLen) {
String suffix = "b\r\nX";
String buffer = new String(new char[prefixLen]).replace("\0", "a") + suffix;
Scanner scanner = new Scanner(buffer);
String pattern = "b\\R";
System.out.printf("=================\nTest String (Len=%d): '%s'\n'%s' found with horizon=0 (w/o bound): %s\n", buffer.length(), convertLineEndings(
buffer), pattern, convertLineEndings(scanner.findWithinHorizon(pattern, 0)));
System.out.printf("'X' found with horizon=1: %b\n", scanner.findWithinHorizon("X", 1) != null);
scanner.close();
}
private static String convertLineEndings(String string) {
return string.replaceAll("\\n", "\\\\n").replaceAll("\\r", "\\\\r");
}
...产生此输出(为格式化/简洁而编辑):
=================
Test String (Len=5): 'ab\r\nX'
'b\R' found with horizon=0 (w/o bound): b\r\n
'X' found with horizon=1: true
=================
Test String (Len=1026): 'a ... ab\r\nX'
'b\R' found with horizon=0 (w/o bound): b\r
'X' found with horizon=1: false
对我来说,这看起来像一个错误!我认为扫描仪应该与suffix
相匹配,模式与输入文本中显示的位置无关(只要prefix
不参与模式)。 (我也发现了可能相关的Open JDK Bugs 8176407和8072582,但这是常规的Oracle JDK 8u111)。
但是我可能已经错过了一些关于扫描器或特定\R
模式使用的建议(或Open JDK,以及Oracle在这里对相关类有相同的(??)实现?)...因此问题!
两个建议:
我认为你应该以这种方式测试X:
System.out.printf("'X' found with horizon=1: %b\n",
scanner.findWithinHorizon("X", prefixLen) != null);
(因为除0之外的任何东西作为水平参数将搜索限制为一定数量的字符。这已经在方法的名称中。视野范围就是方法所见。)
也许你的文件编码有问题。您的扫描仪可能会选择错误的默认编码。尝试沿着这条线:
new Scanner(file, "utf-8");