在一次偶然测试中, 发现了一个关于反斜杠的小问题, 因对此类特殊字符,平常使用较少,所以花了一些时间去解决问题, 并且觉得此问题比较有趣, 故整理记录一下,方便后续解决同类问题.
一 问题引入
在一些特殊的应用场景中,需要对数据进行过滤,将一些非法的字符进行拦截,过滤,替换等等, 常见的场景如一些敏感的词语过滤,比如一些游戏ID等不允许特殊词语和字符等,甚至应用在某些项目为防止xss攻击等.
如下Demo案例展示, 要求将请求参数即reqStr字符串中的特殊字符替换为空字符串, 以防止特殊字符污染源数据.
public class Demo {
/**
* 常见的特殊字符
*/
private static String[] specialStr = new String[]{"/", "\\" };
/**
* 测试字符
*/
private static String reqStr = "123456/\\";
/**
将特殊字符转换成空字符串
*/
@Test
public void test1() {
for (String str : specialStr) {
if (reqStr.indexOf(str) > -1) {
reqStr = reqStr.replaceAll(str, "");
}
}
System.out.println(reqStr);
}
// 运行结果 : java.util.regex.PatternSyntaxException: Unexpected internal error near index 1
\
}
上述test1方法, 会报错 java.util.regex.PatternSyntaxException: Unexpected internal error near index 1 \
上述测试方法,会抛出异常,主要是正则表达式内部解析异常. 从代码上看, 可能以为没有问题, 但实际得从String提供的replaceAll方法看起.
String部分代码:
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
从代码中可知, replaceAll方法的第一个入参, 实际上是一个正则表达式. 根据debug结果发现, 是反斜杠替换过程中, 抛出正则转换异常.初步怀疑, 是正则表达式中 反斜杠的表示问题. 查询相关资料后,得知,在正则表达式中, 两个反斜杠表示一个反斜杠.
结合replaceAll方法,根据反推法, 如果我们要对反斜杠进行替换, 那么传入的正则regex必须是两个反斜杠(根据正则规定可知),再倒推到字符串中, 字符串中使用两个反斜杠表示一个反斜杠, 所以字符串regex必须是四个反斜杠.
根据上述可知:
- 字符串中 两个反斜杠表示一个反斜杠 -> 用
\\
表示\ - 正则中 四个反斜杠表示一个反斜杠 -> 用
\\\\
表示\
二 解决方法
针对字符串中反斜杠和正则表达式中反斜杠分开表示, 即字符串中反斜杠使用两个反斜杠表示(\\
),而正则表达式中反斜杠使用四个反斜杠表示(\\\\
)
public class Demo {
/**
* 常见的特殊字符
*/
private static String[] specialStr = new String[]{"/", "\\" };
/**
* 测试字符
*/
private static String reqStr = "123456/\\";
/**
将特殊字符转换成空字符串
*/
@Test
public void test2() {
for (String str : specialStr) {
int i = reqStr.indexOf(str);
if (i > -1) {
// 遇到单斜杠, 特殊处理
if ("\\".equals(str)) {
reqStr = reqStr.replaceAll("\\\\", "");
} else {
reqStr = reqStr.replaceAll(str, "");
}
}
}
System.out.println(reqStr);
}
// 运行结果: 123456
}
运行结果: 123456