Java 正则表达式是不是支持排序序列?
Posted
技术标签:
【中文标题】Java 正则表达式是不是支持排序序列?【英文标题】:Do Java regular expressions support collating sequences?Java 正则表达式是否支持排序序列? 【发布时间】:2019-03-16 00:57:54 【问题描述】:我正在尝试针对测试字符串chchch
使用正则表达式([[.ch.]]*)c
。根据the spec:
[[.ch.]]*c 匹配字符串 chchch 中的第一个到第五个字符
当我在 Java 中测试它时,它确实匹配了这些字符,但 [[ch]]*c
也是如此。因此,我不确定整理符号是否受到尊重。是吗?
【问题讨论】:
【参考方案1】:TL;DR - 没有。
您正在阅读/引用的规范是 Open Group 的 SUS(Single UNIX® Specification)版本的正则表达式IEEE POSIX 的一部分(P便携式O运行S系统IuniX接口>) 收集标准。 (见https://www.regular-expressions.info/posix.html¹)
一般来说,只有符合 POSIX 的正则表达式引擎才能完全支持 POSIX bracket expressions,这本质上是其他正则表达式风格所称的字符类,但具有一些特殊功能,其中之一是 [.
和 .]
被解释为在表达式中使用时排序序列的开始和结束。
不幸的是,很少有正则表达式引擎是 POSIX 兼容的,事实上,一些声称实现 POSIX 正则表达式的引擎只是使用由 POSIX 定义的正则表达式语法并且没有完整的locale 支持。因此,它们没有实现所有/任何括号表达式功能/怪癖。
Java 的正则表达式绝不是 POSIX 兼容的,从 Regular Expression Engine Comparison Chart ² 可以看出。它的regex
包实现了一个“类似Perl”的正则表达式引擎,缺少一些功能(例如条件表达式和cmets),但包括一些额外的功能(例如所有格量词和可变长度但有限的后视断言)。
Perl 和 Java 都不支持与排序相关的括号分隔符 [=
和 =]
(字符等价),或 [.
和 .]
(排序顺序)。 Perl 确实支持使用 POSIX [:
和 :]
分隔符的字符类,但 Java 仅支持使用 \p
运算符(有一些注意事项,如 here 所述)。
那么,Java 中的正则表达式 [[.ch.]]*c
是怎么回事? (我忽略了捕获组,因为它不会改变分析。)
好吧,事实证明Java 的regex
包在其字符类中支持unions。这是通过嵌套实现的。例如,[<em>set1</em>[<em>set2</em>]]
等价于[<em>set3</em>]
,其中<em>set3</em>
中的字符是<em>set1</em>
中的字符和<em>set2</em>
中的字符的并集。 (顺便说一句,请注意 [[<em>set1</em>][<em>set2</em>]]
和 [[<em>set1</em>]<em>set2</em>]
也会产生相同的结果。)
所以,[[.ch.]]
只是包含空字符集与字符类[.ch.]
中的字符集的并集的字符类,所以它基本上与字符类[.ch.]
相同。这相当于[.ch]
(因为第二个.
是多余的),因此[[.ch.]]*c
与[.ch]*c
相同。
同样,[[ch]]*c
简化为 [ch]*c
。
最后,由于字符串chchch
中没有任何.
字符,正则表达式[.ch]*c
和[ch]*c
将产生相同的结果。 (尝试对字符串c.hchch
进行测试以查看差异并证明上述内容。)
注意事项:
对于演示整理序列或检测它们是否已实现,这不是一个很好的示例,因为当支持整理序列时,[[.ch.]]*c
将匹配chchch
中的chchc
(并且ch
是有效的当前语言环境中的序列)以及何时不是但联合是。
一个更好的演示/测试是使用正则表达式[[.ch.]]
和测试字符串ch
:
ch
,则支持排序序列。
任何其他匹配意味着它们不是。
如果返回错误,它们可能会得到支持,因为如果ch
在当前语言环境中不是有效序列(它是捷克语言环境中的有效整理序列),就会发生这种情况:
如果错误表明ch
不是有效的整理序列,则它们受支持。
如果返回的错误是分隔符/标记[.
和/或.]
无效/不受支持,则不支持整理序列。
如果错误不明确,或者为了保证检查支持的方式,您需要切换到捷克语区域设置(并确认 ch
确实是有效的整理序列)或切换到任何其他具有至少一个已定义的整理顺序,可以用来代替ch
。
¹ 我既不是 Jan Goyvaerts,也不隶属于 Regular-Expressions.info 网站。 ² 我也不是CMCDragonkai。
【讨论】:
感谢您的全面回复。需要注意的是,Java 实际上支持 cmets,只要您通过传入 Pattern.COMMENTS 标志或嵌入 (?x) 标志来打开 cmets 模式。 @VictorGrazi 不客气。不过,我有点困惑。 cmets模式的参考是什么? AFAIK cmets 与允许在正则表达式中嵌入 cmets 有关。我不明白这与我的答案有何关系。 您说 Java 的“正则表达式包实现了一个“类 Perl”正则表达式引擎,缺少一些功能(例如条件表达式和 cmets)”。我只是在纠正这一点,Java 并没有缺少 cmets 支持。您可以在模式中指定 (?x),以便忽略空格,并将 # 解释为注释指示符。对吗?以上是关于Java 正则表达式是不是支持排序序列?的主要内容,如果未能解决你的问题,请参考以下文章
JAVASE01---Unit02: 正则表达式 Object 包装类