使用\ R模式的Java扫描程序使用(缓冲区边界问题)

Ozg*_*urH 12 java regex java.util.scanner

执行摘要:\R Java中是否存在任何警告/已知问题(或其他正则表达式模式)Scanner(特别是关于内部缓冲区的边界条件)?

细节:由于我想在潜在的多平台输入文件上进行一些多线模式匹配,我使用了模式\R,根据Patternjavadoc是:

任何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");
}
Run Code Online (Sandbox Code Playgroud)

...产生此输出(为格式化/简洁而编辑):

=================
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
Run Code Online (Sandbox Code Playgroud)

对我来说,这看起来像一个错误!我认为扫描仪应该与suffix模式匹配,与输入文本中显示的位置无关(只要prefix不涉及模式).(我还发现了可能相关的Open JDK Bugs 81764078072582,但这与常规的Oracle JDK 8u111相同).

但是我可能已经错过了一些关于扫描程序或特定\R模式使用的建议(或Open JDK,以及Oracle在这里对相关类有相同的(??)实现?)...因此问题!

Pat*_*ker 1

我在 Ideone 上测试了这段代码,它在最新版本的 Java 上不再返回“false”。

https://www.ideone.com/4wwYSj

但是,如果我被困在旧版本或仍然存在错误的版本上,并且我需要一个通用解决方案而不是这个示例的解决方法,那么我可能会尝试制作一个类似于但\R强制额外字节的正则表达式窥视案件\r。请注意,文档中所谓的“等效”模式并不是真正的等效,因为它实际上需要是原子分组。所以你最终可能会得到这样的结果:

(?>\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029](?=.|\Z))