请选择 进入手机版 | 继续访问电脑版
本站特色:极好的技术研究氛围!所有技术发帖,必有回复! 做最受欢迎的Java论坛

疯狂Java联盟

 找回密码
 加入联盟
查看: 35|回复: 0

正则表达式的陷阱

[复制链接]
发表于 2017-12-6 17:36:28 | 显示全部楼层 |阅读模式
本帖最后由 kongyeeku 于 2017-12-6 17:41 编辑

本文节选自《疯狂Java程序员的基本修养》

下面的陷阱也是来自于我的一个学生,他跟着我学习了2个月之后到美国继续念研究生去了,后来他写封邮件给我:声称他发现了Java的一个bug。下面来看看他发现的bug:
程序清单:codes\05\5.7\StringSplit.java
public class StringSplit
{
         publicstatic void main(String[] args)
         {
                   Stringstr = "java.is.funny.www.crazyit.org";
                   //将这个字符串以点号(.)分割成多个字符
                   String[]strArr = str.split(".");
                   for(String s : strArr )
                   {
                            System.out.println(s);
                   }
         }
}
上面程序非常简单,程序提供了一个包含多个点号(.)的字符串,接着程序调用String提供的split()方法、以点号(.)作为分割符来分割这个字符串,程序希望返回该字符串被分割后得到的字符串数组,运行该程序试试看,结果我们发现程序什么都没有输出。
提示:从JDK 1.4开始,JavaString类提供了split()方法进行字符串分割,JDK 1.0原来提供的StringTokenizer基本上已经属于“历史遗物”了,大部分时候程序没必要使用这个类来进行字符串分割。
对于上面程序的运行结果,我们要注意如下两点:
q     String提供的split(String regex)方法需要的参数是正则表达式。
q     正则表达式中点号(.)可匹配任意字符。
了解上面这两点规律之后,不难理解上面程序户为何没有看到希望的分割结果:因为正在表达式中点号(.)可以匹配任意字符,因此上面程序实际上不是以点号(.)作为分割符,而是以任意字符作为分隔符。为了实现以点号(.)作为分割符的目的,必须对点号进行转义。将上面程序改为如下形式即可:
public class StringSplit
{
         publicstatic void main(String[] args)
         {
                   Stringstr = "java.is.funny.www.crazyit.org";
                   //将这个字符串以点号(.)分割成多个字符
                   String[]strArr = str.split("\\.");
                   for(String s : strArr )
                   {
                            System.out.println(s);
                   }
         }
}
运行上面程序就可以看到字符串以点号(.)分割的结果了,这就是我们需要的结果。由此可见,这并不是Java的bug,只是对Java中某些特性掌握不够精准造成的误解。
从JDK 1.4开始,Java加入了对正则表达式的支持,String类也增加了一些方法用于支持正则表达式,具体有如下方法:
q     matches(String regex):判断该字符串是否匹配指定正则表达式。
q     String replaceAll(String regex,String replacement):将字符串中所有匹配指定正则表达式的子串替换成replacement后返回。
q     String replaceFirst(Stringregex, String replacement):将字符串中第一个匹配指定正则表达式的子串替换成replacement后返回。
q     String[] split(String regex):以regex正则表达式匹配的子串作为分割符来分割该字符串。
上面4个方法都需要一个regex参数,这个参数就是正则表达式,因此使用这些方法时需要特别小心。String提供了一个与replaceAll功能相当的方法:
q     replace(CharSequence target,CharSequence replacement):将字符串中所有target子串替换成replacement后返回。
这个普通replace()方法就不支持正则表达式,开发中必须区别对待replaceAll和replace()两个方法,看如下程序:
程序清单:codes\05\5.7\StringReplace.java
public class StringReplace
{
         publicstatic void main(String[] args)
         {
                   Stringclazz = "org.crazyit.auction.model.Item";
                   //使用replace就比较简单
                   Stringpath1 = clazz.replace("." , "\\");
                   System.out.println(path1);
                   //使用replaceAll复杂多了
                   Stringpath2 = clazz.replaceAll("\\." , "\\\\");
                   System.out.println(path2);
         }
}
上面程序中先提供了"org.crazyit.auction.model.Item"字符串,程序试图将该字符串中的点号(.)替换成反斜线(\\),如果程序使用replace()方法进行替换,因为replace()方法的参数只是普通字符串,并不是正则表达式,因此使用clazz.replace(".", "\\");即可;如果使用replaceAll()方法进行替换, 因为replaceAll()方法的参数是正则表达式,所以第一个参数需要写作"\\.",其中\\用于生成转义的反斜线;第二个参数为"\\\\",其中前2条斜线生成转义的反斜线,后2条斜线生成要替换的反斜线。
您需要登录后才可以回帖 登录 | 加入联盟

本版积分规则

视频、代码、电子书下载
请关注"疯狂图书"公众号
QQ交流1群: 545923995  未满

小黑屋|手机版|Archiver|疯狂Java联盟 ( 粤ICP备11063141号 )

GMT+8, 2017-12-18 20:40 , Processed in 0.222439 second(s), 6 queries , File On.

快速回复 返回顶部 返回列表