Java replaceAll 正则表达式错误

标签 java regex replaceall

我想把所有的“*”都变成“.*”,除了“\*”

String regex01 = "\\*toto".replaceAll("[^\\\\]\\*", ".*");
assertTrue("*toto".matches(regex01));// True

String regex02 = "toto*".replaceAll("[^\\\\]\\*", ".*");
assertTrue("tototo".matches(regex02));// True

String regex03 = "*toto".replaceAll("[^\\\\]\\*", ".*");
assertTrue("tototo".matches(regex03));// Error

如果“*”是第一个字符,则会发生错误: java.util.regex.PatternSyntaxException: 索引 0 附近的悬挂元字符“*”

什么是正确的正则表达式?

最佳答案

这是目前唯一能够连续处理多个转义\的解决方案:

String regex = input.replaceAll("\\G((?:[^\\\\*]|\\\\[\\\\*])*)[*]", "$1.*");

工作原理

让我们打印字符串 regex 以查看正则表达式引擎解析的实际字符串:

\G((?:[^\\*]|\\[\\*])*)[*]

((?:[^\\*]|\\[\\*])*) 匹配不是 \* 的字符序列,或转义序列 \\\*。我们匹配所有我们不想接触的字符,并将其放入一个捕获组中,以便我们可以将其放回去。

[*] 所述,上述序列后跟一个未转义的星号。

为了确保当正则表达式无法匹配未转义的*时我们不会“跳转”,\G用于确保下一个匹配只能从字符串的开头开始,或者从最后一个匹配结束的地方开始。

为什么这么长的解决方案? 有必要,因为look-behind 构造要检查是否有连续的 \ 前面的数* 为奇数或偶数不受 Java 正则表达式的正式支持。因此,我们需要从左到右使用字符串,同时考虑转义序列,直到遇到未转义的 * 并将其替换为 .*

测试程序

String inputs[] = {
    "toto*",
    "\\*toto",
    "\\\\*toto",
    "*toto",
    "\\\\\\\\*toto",
    "\\\\*\\\\\\*\\*\\\\\\\\*"};

for (String input: inputs) {
    String regex = input.replaceAll("\\G((?:[^\\\\*]|\\\\[\\\\*])*)[*]", "$1.*");
    System.out.println(input);
    System.out.println(Pattern.compile(regex));
    System.out.println();
}

示例输出

toto*
toto.*

\*toto
\*toto

\\*toto
\\.*toto

*toto
.*toto

\\\\*toto
\\\\.*toto

\\*\\\*\*\\\\*
\\.*\\\*\*\\\\.*

关于Java replaceAll 正则表达式错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30076414/

相关文章:

java - 在 Android 应用程序中使用 Maven 项目

java - Java 中的 64 位媒体框架

javascript - Codemirror如何创建模式

php - Zend Framework 2 - 注释表单、RegEx 验证和自定义错误消息

java - Java 中的有效括号

java - 在 Java 中使用 replace 和 replaceAll 替换连续的相同字符

java - 是否可以使用 "$1"作为另一个方法的参数并将返回的字符串放在 .replaceAll 中的位置?

java - Android - 如何使用索引处的对象解析 json

javascript - John Resig Micro 模板错误

java - 按照 MVC 模式在 Java 中实现 JFileChooser