Java 8中使用java.util.regex实现逐字匹配的问题:如何避免用户输入特殊字符引发正则语法异常?
嗨,我来帮你解决这个问题!你遇到的情况其实很典型:当用户输入的文本里包含正则表达式的特殊字符(比如反斜杠\、星号*、加号+这类)时,直接把它们当作正则模式编译就会触发PatternSyntaxException——因为正则引擎会把这些字符当作语法指令,而不是你想要匹配的字面文本。
你完全不需要手动去转义每一个特殊字符,Java的java.util.regex.Pattern类已经提供了现成的解决方案,有两种简单的方式可以实现逐字匹配:
方法一:使用Pattern.quote()方法
这个静态方法会把输入的字符串转换成一个正则表达式的字面量模式,自动将所有特殊字符转义,让正则引擎把整个字符串当作普通文本处理。
修改你的测试代码如下:
import org.junit.jupiter.api.Test; import java.util.regex.Matcher; import java.util.regex.Pattern; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; class GenericTest { @Test void someTest() { // 用户输入的反斜杠,在Java字符串中需要用两个反斜杠表示 String userInput = "\\"; // 使用quote()将输入转为字面量正则模式 Pattern pattern = Pattern.compile(Pattern.quote(userInput)); Matcher matcher = pattern.matcher("\\"); boolean hasMatch = matcher.find(); assertTrue(hasMatch); assertEquals("\\", matcher.group()); } }
Pattern.quote()的原理是把输入字符串用正则的字面量标记\Q和\E包裹起来——\Q表示开始字面量模式,\E表示结束,中间的所有字符都会被当作普通文本解析,不会触发正则语法。
方法二:使用Pattern.LITERAL编译标志
你也可以在编译Pattern时传入Pattern.LITERAL标志,告诉正则引擎把整个模式字符串当作字面量处理,忽略所有正则特殊字符的语法意义:
// 替换编译语句为下面这行即可 Pattern pattern = Pattern.compile(userInput, Pattern.LITERAL);
这种方式和quote()效果一致,适合你明确需要将整个模式作为字面量匹配的场景。
为什么你的原代码会报错?
你原代码里直接编译Pattern.compile("\\"),在正则引擎看来,单个反斜杠是一个不完整的转义序列(正则里反斜杠需要跟一个字符来表示转义,比如\d表示数字),所以会抛出PatternSyntaxException。而用上面两种方法处理后,反斜杠会被当作普通字符,不会被解析成正则语法。
这两种方法都能完美解决用户输入任意文本作为匹配模式的问题,不需要你手动处理每个特殊字符,非常省心!
内容来源于stack exchange

