1.背景
小王是一位程序员,今天,他在处理数据时,使用了"\"反斜杠作为分割符,解析数据时,他使用了String的split(regex)方法来截取数据,但是运行的时候出现了:
java.util.regex.PatternSyntaxException: Unexpected internal error near index 1
\
的异常,我们来看看他的代码:
String regex="\\";
String[] datas=originData.split(regex);
最后他将正则改成:
String regex="\\\\";
正确的匹配了数据,但ide不报错,编译器也不报错,运行报错了,咋回事呢? 我们一起来看下。
2.异常解释
/**
* Internal method used for handling all syntax errors. The pattern is
* displayed with a pointer to aid in locating the syntax error.
*/
private PatternSyntaxException error(String s) {
return new PatternSyntaxException(s, normalizedPattern, cursor - 1);
}
java.util.regex.PatternSyntaxException主要用于处理编译期未检测到引发的异常, 用来指示正则表达式中的语法错误 ,看到这里我们已经知道了是我们正则表达式语法出现了问题,但问题是,我们写的用于匹配单斜杠"\"的正则:String regex="\\"; 是正确的,问题出现在哪里? 我们继续深入研究一下String的split方法!
3.源码分析
为了方便打断点,我们将正则:String regex="\\";的声明方式,改变成:String regex=new String("\\");
String regex= new String("\\");
String data="1\2\3";
data.split(regex);
最后我们发现:
1.String类加载时同时加载了Pattern的静态方法预加载了一些默认的正则表达式(Effective Java中建议使用正则时最好使用Pattern而不使用String.matches()方法,matches里每次都会创建一个Pattern实例,创建Pattern实例是一个成本非常高的过程,因为需要将正则表达式翻译成一个有限状态机)
2.在String的split方法中使用了Pattern的静态方法来编译额外的正则表达式
Pattern.compile(regex).split(this, limit);
上述方法中,调用了
3.compile()方法中校验了校验正则表达式字符
时此时pattern的长度为 1,value='\\', 而此时游标的长度为2,导致了异常的发生
该异常的发生是因为正则匹配的字符本身具有的特殊性:如,"\"、"?"、“{“、“}”等,他们本身需要被转义符转义,因此需要匹配以上字符时,正则表达式一定要加"\\",如:"\\{"匹配 “{}”