当前位置: 首页 > 知识库问答 >
问题:

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

湛光明
2023-03-14

执行摘要:在Java的Scanner(尤其是关于内部缓冲区边界条件)中,\R(或其他regex模式)的使用是否有任何警告/已知问题?

详细信息:因为我想对潜在的多平台输入文件进行多行模式匹配,所以我使用了带有< code>\R的模式,根据< code>Pattern javadoc:

任何Unicode换行符序列,都等价于\u000D\u000A|[\u000A\u000B\u000C\u000D]

总之,我在一个测试文件中注意到,应该解析十六进制转储块的循环被截断了。经过一些调试,我注意到它结束的行是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

对我来说,这看起来像一个错误!我认为扫描仪应该以同样的方式将< code >后缀与模式相匹配,而不管它们出现在输入文本中的什么位置(只要< code >前缀不与模式相关)。(我还发现了可能相关的开放式JDK错误8176407和8072582,但这是针对常规Oracle JDK 8u111的)。

但我可能遗漏了一些关于scanner或特定\R模式用法的建议(或者Open JDK和Oracle有相同的(??)在这里实现相关类?)。。。于是问题来了!

共有2个答案

阚乐湛
2023-03-14

两条建议:

我认为你应该这样测试X:

System.out.printf("'X' found with horizon=1: %b\n", 
    scanner.findWithinHorizon("X", prefixLen) != null);

(因为除0以外的任何参数都将搜索限制在一定数量的字符。这已经在方法的名称中。地平线是方法看到的最远的地方。)

也许您的文件编码有问题。您的扫描仪可能会选择错误的默认编码。试试这样的方法:

new Scanner(file, "utf-8");
孔宇
2023-03-14

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

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

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

<代码>(?

 类似资料:
  • 我写了这个正则表达式

  • 问题内容: 如何将扫描仪的定界符设置为;或换行? 我试过: 但这不起作用。 问题答案: 通常,在模式中,您需要将翻倍。 所以,尝试 要么 编辑 :如果是问题,则可能要尝试以下操作: 它匹配的一个或多个,和。 注意 :我还没有尝试过这些。

  • 问题内容: 我正在尝试读取具有多个单词的字符串,即。洛杉矶或纽约市。如果有两个词并将它们分割在变量之间,则使用scanner.next()进行“出发”和“到达”只会读取第一个。nextLine()也不是很幸运。这是我的代码: 我知道这很简单,但我还没有弄清楚。 这是上面的代码的输入/输出: 输入航班号:29 输入出发城市:(立即跳至下一行) 输入到达城市: -—我真正想要的是---- 输入航班号:

  • 我有两个do-while循环用于进行自定义输入验证。问题是它会自动进入下一个do while循环。正确插入名称后,我必须放置一个新的下一行():name=scanner。nextLine() 我知道当光标停留在那里时,nextLine()会出现“小故障”,您必须调用nextLine()才能继续。资料来源:https://www.geeksforgeeks.org/why-is-scanner-sk

  • 我正在用Java编程 我正在尝试编写代码,以识别用户是否在基于控制台的程序中按enter键。 我如何使用java做到这一点。有人告诉我,这可以使用Scanner或缓冲输入阅读器来完成。我不明白(或不知道如何使用)缓冲输入阅读器。 我试着用scanner来做这件事,但按了两次enter键后,程序终止,无法工作 谢啦 --编辑--以下代码使用字符串的方法而不是 如何做到这一点,使用缓冲输入读取器的好处

  • 这个代码中的对象扫描仪有什么问题? 当我选择案例2时,我得到了这个错误: 我认为scanner首先声明为int,现在在切换之后,我用类型double收集答案。我不太确定,我需要更多地了解scanner类是如何工作的。