我想把所有的“*”都变成“.*”,除了“\*”
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/