【问题标题】:Issues with the Java 8 linebreak RegEx escape character in EclipseEclipse 中 Java 8 换行符 RegEx 转义字符的问题
【发布时间】:2017-01-24 19:04:26
【问题描述】:

我想在我的方法中使用正则表达式解析格式如下所述的字符串,但是即使 RegExr 等在线 RegEx 工具显示我的表达式应该匹配它却不匹配。

我使用的表达式是(@(\\d+))[(\r\n)\n](((0|1){"+width+"}[(\r\n)\n]){"+height+"}),其中widthheight 是文本块所需宽度和高度的整数值。

我想从我的文件中检索的文本块的格式如下:

@200
0000000000
0000011001
1100100000
0101001101
1110001110

@500
0000000000
0000011001
1100100000
0101001101
1110001110

etc.

(这里,width 将是 10 和 height 5)

想要使用 Matcher.find() 方法来检索每个块,但表达式甚至找不到任何东西。

我怀疑我处理换行符的方式存在问题,但是当我想尝试使用新的 Java 8 \R 通用换行符转义字符时,Eclipse 显示错误“无效转义序列”。

【问题讨论】:

  • [(\r\n)\n] 不会像您认为的那样做。这是一个将匹配(\r\n)\n 的字符类。两次列出\n 是没有意义的,所以写[()\n\r] 意味着同样的事情。您可能打算使用\r?\n,这意味着\r\n\n
  • 另外,你有太多的括号,除非你真的想捕捉所有这些。无需捕获,正则表达式应为"@\\d+\r?\n(?:[01]{"+width+"}\r?\n){"+height+"}"
  • 或者只使用\R 来表示任何类型的换行符。
  • @Holger OP 已经尝试使用\R,所以只是说使用它没有帮助。现在,告诉 OP 记住对字符串文字中的 \ 进行 Java 转义会很有用,所以:Maximilian, 记住写 \\R,因为 \R 是无效的 Java 转义序列,但 "\\R" 变为 \R 以供正则表达式引擎查看,并且 支持 \R 转义序列(在 Java 8+ 中)。
  • 这就是 OP 没有显示实际源代码时的问题。所以不清楚我们是在谈论正则表达式语法还是 Java 字符串文字语法。在谈论 Java 源代码语法时,我通常使用 "\\R",而在谈论正则表达式语法(或任何其他类型的 DSL)时,我通常使用 \R(不带引号)。真正的乐趣始于谈论生成或解析源代码,即需要"\"\\\\R\""...

标签: java regex eclipse parsing java-8


【解决方案1】:

只是为了完整性,因为您的问题描述中出现了转义问题:\ 在字符串文字中是特殊的(在"..." 部分)。多亏了它,我们可以编写许多通常不允许在字符串中使用的字符,例如行分隔符。使用\,我们可以将它们写为\r\n(或通过许多其他形式:十六进制索引\uXXXX,八进制索引\OOO)。
但是因为它很特殊,我们还需要一种方法来编写\ 符号本身。因此,为了不提供另一个允许我们创建\ 文字的特殊字符,我们使用另一个\转义它,例如"\\"。例如"\r\n\\"字面量代表3个字符:回车换行\

这就是为什么要创建表示\d 的字符串文字,以便我们可以将其传递给正则表达式引擎,我们需要将其写为"\\d"


现在回到答案的主要部分。

[..]单个 字符类。所以它可以匹配描述集中的单个字符。所以:

  • 因为(..) 用于对在[..] 中不可能的字符系列进行分组,() 失去了它的意义,因此[(\r\n)\n] 代表单个(\r\n)(注意\r\n 代表单个字符,代表换行符。另外一个\n 是多余的)

  • 由于\R在单个\r\n(和few others)旁边也可以表示\r\n序列,它不能在[..]内部使用,因为字符集只能匹配单个字符。

    如果你在[..] 中使用\R,你会得到PatternSyntaxException: Illegal/unsupported escape sequence 异常。 Java 通常允许在字符类中的任何字符之前添加\\

    • 表示预定义的字符类:\\d\\w

    但在它不改变任何东西的情况下:

    • \\r \\n \\t 它只是表示与字符串文字相同的字符"\r" "\n" "\t"
    • 或在没有任何特殊含义的字符之前,所以我们真的不需要转义它们\\x\\y\\h

    但是它不允许您尝试转义在[...] 之外具有特殊含义的字符,并且不能保证代表单个字符,例如\R 或@987654374 @ (word boundaries 因为它不代表字符,而是在单词之前/之后放置

你可以做的是使用\R 而不是 [(\r\n)\n](但不要忘记也像\d那样在String中转义它的\部分)。您还可以删除最外层的 (...) 对,因为整个匹配项已存储在第 0 组中,因此您无需为此添加另一个组。

重写正则表达式的最简单方法之一是:

String regex = "@(\\d+)\\R([01]{"+width+"}\\R){"+height+"}";

但由于您可能不想包含最后一行分隔符,因此可以随意使用? 量词将最后一个\R 设为可选,并且不情愿地在它之后添加另一个?

String regex = "@(\\d+)\\R([01]{"+width+"}\\R??){"+height+"}";

DEMO

【讨论】:

  • 对 cme​​ts 的精彩回顾。也想添加我的最后一条评论,以解释为什么 \R 不能不转义但 \r 可以吗?
  • @Andreas 我不确定 OP 问题是否缺少通过\\R 转义\R。我怀疑 OP 使用了[\\R],并且由于\\R 不能在那里使用(因为它也可以代表\r\n 对,如答案中所述)他得到Illegal/unsupported escape sequence 错误。 [\\b] 也有类似的问题,因为 \b 不代表单个字符,而是 place(锚点)。将尝试将其添加到答案中。
  • 我认为“无效的转义序列”来自字符串文字中的 \R,因为 OP 说“Eclipse 显示”,这意味着它是编译器错误,而 [\\R] 将是运行时错误。当然,您还会在 Eclipse 中看到运行时错误,因此您可能是对的。 ;-)
  • 是的,“Eclipse 显示”可以来自编译,但 OP 也可能在谈论堆栈跟踪,所以它有点模糊。但是现在在阅读 cmets 之后,您似乎对 \R\\R 的看法是正确的,所以感谢您指出这一点。
猜你喜欢
  • 1970-01-01
  • 2011-03-14
  • 1970-01-01
  • 2011-04-19
  • 2013-05-11
  • 1970-01-01
  • 2013-08-22
  • 1970-01-01
相关资源
最近更新 更多