Java 模式涉及美元符号($)时的正则表达式
当涉及到匹配涉及美元符号的子模式时,我遇到了一点问题。例如,考虑下面的一大块文本:Java 模式涉及美元符号($)时的正则表达式,java,regex,Java,Regex,当涉及到匹配涉及美元符号的子模式时,我遇到了一点问题。例如,考虑下面的一大块文本: (en $) foo oof ($). ofo (env. 80 $US) 我正在使用以下正则表达式: Pattern p = Pattern.compile( "\\([\\p{InARABIC}\\s]+\\)|\\([\\p{InBasic_Latin}\\s?\\$]+\\)|\\)([\\p{InARABIC}\\s]+)\\(", Pattern.CA
(en $) foo
oof ($).
ofo (env. 80 $US)
我正在使用以下正则表达式:
Pattern p = Pattern.compile(
"\\([\\p{InARABIC}\\s]+\\)|\\([\\p{InBasic_Latin}\\s?\\$]+\\)|\\)([\\p{InARABIC}\\s]+)\\(",
Pattern.CASE_INSENSITIVE);
public String replace(String text) {
Matcher m = p.matcher(text);
String replacement = m.replaceAll(match -> {
if (m.group(1) == null) {
return m.group();
} else {
return "(" + match.group(1) + ")";
}
});
return replacement;
}
但无法匹配包含
$
的文本此代码类似于replaceAll(regex,replacement)
。问题是,$
不仅在regex参数中是特殊的,而且在替换中,它可以用作组匹配的引用,如$x
(其中x
是组ID)或${groupName}
,如果您的regex具有(?subsectex)
这允许我们编写类似于
String doubled = "abc".replaceAll(".", "$0$0");
System.out.println(doubled); //prints: aabbcc
它将用其两个副本替换每个字符,因为每个字符都将由
匹配并放入组0中,因此$0$0
表示该匹配字符的两个重复
但是在您的案例中,您的文本中有$
,因此当它匹配时,您将用它本身替换它,因此您在替换$
中使用,而没有任何关于组ID(或组名)的信息,这将导致非法组引用
解决方案是在替换零件中转义$
。您可以使用\
手动执行此操作,但最好使用为此目的设计的方法(如果正则表达式会演变,并且您需要逃避更多事情,则此方法应与正则表达式引擎一起演变,这将为您以后节省一些麻烦)
因此,请尝试将代码更改为
public String replace(String text) {
Matcher m = p.matcher(text);
String replacement = m.replaceAll(match -> {
if (m.group(1) == null) {
return Matcher.quoteReplacement(m.group());
// ^^^^^^^^^^^^^^^^^^^^^^^^
} else {
return Matcher.quoteReplacement("(" + match.group(1) + ")");
// ^^^^^^^^^^^^^^^^^^^^^^^^
}
});
return replacement;
}
}
此代码类似于replaceAll(regex,replacement)
。问题是,$
不仅在regex参数中是特殊的,而且在替换中,它可以用作组匹配的引用,如$x
(其中x
是组ID)或${groupName}
,如果您的regex具有(?subsectex)
这允许我们编写类似于
String doubled = "abc".replaceAll(".", "$0$0");
System.out.println(doubled); //prints: aabbcc
它将用其两个副本替换每个字符,因为每个字符都将由
匹配并放入组0中,因此$0$0
表示该匹配字符的两个重复
但是在您的案例中,您的文本中有$
,因此当它匹配时,您将用它本身替换它,因此您在替换$
中使用,而没有任何关于组ID(或组名)的信息,这将导致非法组引用
解决方案是在替换零件中转义$
。您可以使用\
手动执行此操作,但最好使用为此目的设计的方法(如果正则表达式会演变,并且您需要逃避更多事情,则此方法应与正则表达式引擎一起演变,这将为您以后节省一些麻烦)
因此,请尝试将代码更改为
public String replace(String text) {
Matcher m = p.matcher(text);
String replacement = m.replaceAll(match -> {
if (m.group(1) == null) {
return Matcher.quoteReplacement(m.group());
// ^^^^^^^^^^^^^^^^^^^^^^^^
} else {
return Matcher.quoteReplacement("(" + match.group(1) + ")");
// ^^^^^^^^^^^^^^^^^^^^^^^^
}
});
return replacement;
}
}
您使用的是find()
还是matches()
?对不起,忘了提及我使用的是matcher您使用的是匹配项
还是查找
<代码>匹配项
不起作用,因为字符串与正则表达式不匹配。此外,如果您正确地使用了find
,即使这样,您的第三个示例也不会提供任何信息,因为它包含一个
,而在正则表达式中没有“通常的元字符是字符类中的普通字符,不需要用反斜杠转义”。“如果转义字符类中的常规元字符,则正则表达式可以正常工作,但这样做会显著降低可读性。”您使用的是find()
还是matches()
?抱歉忘了提及我使用的是Matcher您使用的是matches
还是find
?matches
将不起作用,因为您的字符串与正则表达式不匹配。此外,如果您正确使用了find
,即使是这样,您的第三个示例也不会给您任何东西,因为其中包含一个不存在的
在正则表达式中,“通常的元字符是字符类中的普通字符,不需要反斜杠转义”。“如果转义字符类中的常规元字符,正则表达式可以正常工作,但这样做会显著降低可读性。”谢谢,我保留此模式:pattern p=pattern.compile(“\\([\\p{InARABIC}\\s]+\\)\\([\\p{InBasic\u Latin}\\s?\\$]+\\)([\\p{InARABIC}\\s]+)\(“,Pattern.Pattern不区分大小写)
应该是这样的,不必客气。顺便说一句,我不知道你为什么要使用模式。不区分大小写的标志。通常当正则表达式包含显式字符,如a
b
时使用它,你希望它们也表示a
和b
,但字符类如\w
,我假设\p{InBasic\u Latin}
默认情况下应包含任何字符的所有形式(大写和小写)。这不适用于\p{InARABIC}
,还是您添加该标志只是为了安全?我保留该标志只是为了安全,正如您所提到的。谢谢,我保留此模式:模式p=pattern.compile([\\p{InARABIC}\\s]+\\)|\\([\\p{InBasic\u Latin}\\s?\\$]+\\)([\\p{InARABIC}\\s]+)\\(“,Pattern.Pattern不区分大小写)
应该是这样的,不必客气。顺便说一句,我不知道你为什么要使用模式。不区分大小写的标志。通常当正则表达式包含显式字符,如a
b
时使用它,你希望它们也表示a
和b
,但字符类如\w
,我假设默认情况下,\p{InBasic\u Latin}
应包含任何字符的所有形式(大写和小写)。这不适用于\p{InARABIC}
,或者您添加该标志只是为了安全?我保留该标志只是为了安全,正如您所述。