编译具有字符类和字边界的详细Java正则表达式时出错
为什么此模式无法编译:编译具有字符类和字边界的详细Java正则表达式时出错,java,regex,verbose,Java,Regex,Verbose,为什么此模式无法编译: Pattern.compile("(?x)[ ]\\b"); 错误 ERROR java.util.regex.PatternSyntaxException: Illegal/unsupported escape sequence near index 8 (?x)[ ]\b ^ at java_util_regex_Pattern$compile.call (Unknown Source) 而下面的等效项可以工作吗 Pattern.compile("
Pattern.compile("(?x)[ ]\\b");
错误
ERROR java.util.regex.PatternSyntaxException:
Illegal/unsupported escape sequence near index 8
(?x)[ ]\b
^
at java_util_regex_Pattern$compile.call (Unknown Source)
而下面的等效项可以工作吗
Pattern.compile("(?x)\\ \\b");
Pattern.compile("[ ]\\b");
Pattern.compile(" \\b");
这是Java正则表达式编译器中的错误,还是我遗漏了什么?我喜欢在详细的正则表达式中使用[]
,而不是反斜杠,因为这样可以节省一些视觉噪音。但显然他们不一样
PS:这个问题不是关于反斜杠。它是关于使用包含单个空格的字符类来转义详细正则表达式中的空格,而不是使用反斜杠
详细正则表达式(?x)
和包含单个空格的字符类的组合会使编译器无法识别单词边界转义\b
使用Java进行测试,最高可达1.8.0_151 我喜欢在详细的正则表达式中使用
[]
,而不是反斜杠,因为这样可以节省一些视觉噪音。但显然他们不一样
“[]”
与“\\”
或甚至与“
相同
问题在于开始启用注释模式时的(?x)
。像美国一样
允许在模式中使用空格和注释。在此模式下,将忽略空白,并开始嵌入注释 使用
#
将被忽略,直到行尾。还可以通过嵌入式标志表达式启用注释模式
(?x)
在注释模式下,正则表达式“(?x)[\\]\\b”
与“[\\\\b”
相同,不会编译,因为空字符类[]
不会解析为空,而是像“[\\]”
一样解析(未关闭的字符类包含文字]
)
改用“\\b”
。或者,在注释模式下保留空格,方法是使用反斜杠进行转义:“(?x)[\\]\\b”
或“(?x)\\\\b”
解决方法
除了分别转义与[]
完全相同的空格外,您还可以为整个正则表达式启用x
模式,但在处理需要空格的模式时禁用它,内联:
(?x)match-this-(?-x: with spaces )\\b
^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^
`x` is on off on
或者另一种方法是使用qouting元字符\Q…。\E
:
(?x)match-this-\Q with s p a c e s \E\\b
^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^
`x` is on off on
为什么出现异常
?
在扩展或注释模式(x
)中,空白被忽略,但在不同风格的字符类中处理空格的方式不同
例如,在PCRE中,除了字符类中的空白字符外,所有空白字符都将被忽略。这意味着[]
是一个有效的正则表达式,但Java没有例外:
在此模式下,空白被忽略
句号。因此,此[]
等于此[]
,此[]
无效,并引发PatternSyntaxException
异常
除了JavaScript之外,几乎所有的正则表达式都需要一个字符类来至少有一个数据单元。它们将空字符类视为需要右括号的未闭合集。也就是说,[]
在大多数口味中都是有效的
[]
上不同风格的自由间距模式:
有效PCRE
有效.NET
有效Perl
有效Ruby
有效TCL
无效Java 7
无效Java 8
[]
中的空格,因此正则表达式引擎将您的正则表达式视为[]\\b
如果我们删除
\\b
它将被视为[]
,我们将得到关于未关闭字符类的错误-字符类不能为空,因此直接放置在[
之后的]
将被视为属于该类的第一个字符,而不是关闭字符类的元符号
因此,由于[
未关闭,正则表达式引擎将\b
视为放置在该字符类中。但\b
不能放置在该字符类中(它不表示字符而是“位置”),因此我们看到了关于“不支持的转义序列”(在字符类中,但该部分被跳过)的错误
换句话说,您不能使用[]
在详细模式下(至少在Java中)转义空间。您需要使用“\\”
或“[\\]”“
让我们分析到底发生了什么
请看一下的源代码
允许在模式中使用空格和注释。在此模式中,空格
将忽略,并且以#开头的嵌入注释将被忽略,直到
一行的末尾。
注释模式也可以通过嵌入的标志表达式启用
(?x)。
您的正则表达式将引导您了解这一点
如果你注意到你的代码调用
这不等于ch
,这里抛出一个异常
throw error(s);
这是模式
类中Java的peekPastWhitespace()
方法中的一个错误。将整个问题向下追踪……我决定看一看。让我们从顶部开始敲打这个问题:
compile()
在第1696行调用expr()
expr()
在第1996行调用sequence()
sequence()
在第2063行调用clazz()
,因为满足了[
的情况
clazz()
在第2509行调用peek()
peek()
peekPastWhitespace()
(发布在下面)跳过模式中的所有空格
方法中也存在相同的错误
您的正则表达式被解释为[]\\b
,这是导致
private int parsePastWhitespace(int ch) {
while (ASCII.isSpace(ch) || ch == '#') {
while (ASCII.isSpace(ch))//<----------------Here is the key of your error
ch = temp[cursor++];
if (ch == '#')
ch = parsePastLine();
}
return ch;
}
if (ch != testChar) {
throw error(s);
}
throw error(s);
private int peekPastWhitespace(int ch) {
while (ASCII.isSpace(ch) || ch == '#') {
while (ASCII.isSpace(ch))
ch = temp[++cursor]
if (ch == '#') {
ch = peekPastLine();
}
}
return ch;
}