2. 特殊正则表达式字符
Java正则表达式API(java.util.regex
)中的元字符具有特殊含义。当需要将它们视为普通字符时,必须进行转义。常见需要转义的元字符包括:
<([{\^-=$!|]})?*+.>
⚠️ 这些元字符在正则中有特殊功能,直接使用会导致意外匹配。比如点号.
实际匹配任意字符,而非字面量点号。看这个踩坑示例:
@Test
public void givenRegexWithDot_whenMatchingStr_thenMatches() {
String strInput = "foof";
String strRegex = "foo.";
assertEquals(true, strInput.matches(strRegex)); // 实际匹配到"foof"而非"foo."
}
这里正则foo.
匹配了"foof"——因为点号匹配了任意字符f
。如果我们想精确匹配字面量点号,就需要转义。
3. 字符转义方法
Java提供两种主流转义方式:
3.1. 使用反斜杠转义
在元字符前加反斜杠\
。但注意在Java字符串中,反斜杠本身需要转义,因此要写成\\
:
@Test
public void givenRegexWithDotEsc_whenMatchingStr_thenNotMatching() {
String strInput = "foof";
String strRegex = "foo\\."; // 转义后的点号
assertEquals(false, strInput.matches(strRegex)); // 现在只匹配"foo."而非"foof"
}
✅ 这种方式简单直接,适合转义单个字符。
3.2. 使用\Q和\E标记
用\Q
和\E
包裹需要转义的字符序列,中间所有元字符都会被自动转义:
@Test
public void givenRegexWithPipeEscaped_whenSplitStr_thenSplits() {
String strInput = "foo|bar|hello|world";
String strRegex = "\\Q|\\E"; // 转义管道符|
assertEquals(4, strInput.split(strRegex).length); // 成功按|分割字符串
}
✅ 适合转义包含多个元字符的复杂模式。
4. Pattern.quote() 方法
Pattern.quote(String)
是更优雅的转义方案,它自动在字符串前后添加\Q
和\E
:
@Test
public void givenRegexWithPipeEscQuoteMeth_whenSplitStr_thenSplits() {
String strInput = "foo|bar|hello|world";
String strRegex = "|"; // 原始管道符
assertEquals(4, strInput.split(Pattern.quote(strRegex)).length); // 自动转义
}
⚠️ 注意:quote()
会转义整个字符串。如果需要单独转义特定字符,仍需使用手动转义或替换算法。
5. 转义字符串中的所有特殊字符
当需要批量转义字符串中所有元字符时,可以遍历字符处理:
public void givenStringWithSpecialCharacters_whenUsingCharacterClass_thenReplace() {
String inputString = "#$%^&*() SimpleText123 ";
StringBuilder escapedString = new StringBuilder();
for (char c : inputString.toCharArray()) {
if (!Character.isLetterOrDigit(c)) {
escapedString.append("\\"); // 非字母数字前加反斜杠
}
escapedString.append(c);
}
String expectedOutputString = "\\#\\$\\%\\^\\&\\*\\(\\)\\ SimpleText123\\ ";
assertEquals(expectedOutputString, escapedString.toString());
}
✅ 这种方式适合动态处理用户输入等场景。
6. 更多实战案例
6.1. 替换操作中的转义
使用replaceAll()
时,忘记转义元字符会导致意外结果。比如替换美元符号$
:
@Test
public void givenRegexWithDollar_whenReplacing_thenNotReplace() {
String strInput = "I gave $50 to my brother."
+ "He bought candy for $35. Now he has $15 left.";
String strRegex = "$"; // 未转义
String strReplacement = "£";
Pattern p = Pattern.compile(strRegex);
Matcher m = p.matcher(strInput);
assertThat("替换失败", not(equalTo(m.replaceAll(strReplacement)))); // 断言失败
}
❌ 因为$
在正则中表示行尾,直接使用无法匹配字面量$
。
正确做法是转义$
:
@Test
public void givenRegexWithDollarEsc_whenReplacing_thenReplace() {
String strInput = "I gave $50 to my brother."
+ "He bought candy for $35. Now he has $15 left.";
String strRegex = "\\$"; // 转义后
String strReplacement = "£";
Pattern p = Pattern.compile(strRegex);
Matcher m = p.matcher(strInput);
String output = "I gave £50 to my brother."
+ "He bought candy for £35. Now he has £15 left.";
assertEquals(output, m.replaceAll(strReplacement)); // 替换成功
}
✅ 转义后$
被正确识别为字面量字符。
7. 总结
掌握正则转义是Java开发者的必备技能:
- 核心元字符:
<([{\^-=$!|]})?*+.>
需要特殊处理 - 三种转义方式:
- 反斜杠
\\
:适合单个字符 \Q...\E
:适合字符序列Pattern.quote()
:最简洁的自动转义
- 反斜杠
- 批量转义:通过字符遍历实现
- 常见坑点:替换操作中忘记转义元字符
本文所有代码示例可在GitHub仓库中查看。