何为正则表达式?正则表达式在我看来就是一个特定的字符串规则。
在工作中,字符串操作是非常频繁,正则表达式的用途我总结有以下几点:
1、判断字符串是否满足正则表达式(也就说一个字符串是否满足我们定义的规则)
如:定义一个正则表达式 “^a[a-z]*e$” 表示一个以a开头,以e结尾的任意长度的一串字母
可以用这个正则表达式来检测其它输入的字符串是否满足这个规则。
2、提取输入字符串中的数据
如:定义一个表达式 "(d{4})-(d{1,2})-(d{1,2})", 表示规则为: 四个数字-一到两个数字-一到两个数字
可以用来提取 “yyyy-MM-dd”格式日期字符串中yyyy ,MM ,dd等数据
正则表达中的子模式的应用
在使用子模式过程中,常见两种写法是:1
和 $1
。
(1) 1
是在正则表达式本身中引用分组1的内容,如:
我们要匹配111
这样的连续出现3此的数字,我们可以写出正则:(d)11
,(d)
匹配到第一个1
,后面再引用这个匹配内容,得到111
。
(2) $1
是在替换中调用分组的内容(在正则表达式外面用,多用于使用正则表达式来替换数据),如:
String str = "abc def";
String replaceFirst = str.replaceFirst("(\w+)\s+(\w+)", "$2 $1"); 将字符串前面的部分和后面的部分位置兑换
在java中使用模式匹配取数据时,字符串中会有多个部分匹配,可以通过循环依次取得所有的数据;java通过group取数据有个坑,在取数据之前,Matcher对象必须要先查找一次,先调用find方法
Pattern p6 = Pattern.compile("(?<=\s)\d+(?=\s)"); Matcher matcher6 = p6.matcher("ht 1 3 2 5 as f d 6 "); while(matcher6.find()) { System.out.println(matcher6.group()); }
非捕获组(?:)主要用来做数据分解,不会捕获匹配的数据,如下就会只有一个捕获组,捕获的域名
Pattern p5 = Pattern.compile("(?:http|ftp|svn)://([^/]+)"); Matcher matcher5 = p5.matcher("http://192.168.0.1/689"); if(matcher5.find()) { System.out.println(matcher5.group(1)); }
模式修饰符
模式修饰符在许多程序语言中都支持的,比如最常见的是i
,不区分大小写,如javascript里的/[a-z0-9]/i,表示匹配字母数字,不区分大小写。
在java中需要在编译正则的时候去指定模式。
Pattern p3 = Pattern.compile("a*?b",Pattern.CASE_INSENSITIVE); Matcher matcher3 = p3.matcher("aaBaB"); matcher3.find(); System.out.println(matcher3.group());
或者使用表达式:
模式修饰符:(?mods-mods:)允许出现的模式:x d s m i u
模式修饰范围:(?mods-mods:...)
环视,在不同的地方又称之为零宽断言,简称断言。
就是先从全局环顾一遍正则,(然后断定结果,)再做进一步匹配处理。环视的分组不占位置,book(?=s)匹配books中的book;
环视主要有以下4个用法: (?<=exp)
匹配前面是exp的数据 (?<!exp)
匹配前面不是exp的数据 (?=exp)
匹配后面是exp的数据 (?!exp)
匹配后面不是exp的数据
Pattern p2 = Pattern.compile("(?<=\s)\d+(?=\s)"); Matcher matcher2 = p2.matcher("I'm singing 3 2 dancing"); matcher2.find(); System.out.println(matcher2.group(0));
环视的特点,环视部分是不占宽度的,所以有零宽断言的叫法。
所谓不占宽度,可以分成两部分理解:
1、环视的匹配结果不纳入数据结果
2、环视它匹配过的地方,下次还能用它继续匹配。
如上得到的分组结果是 "3" 而不是“ 3 ”(3旁边有空白符) ,
正则表达式性能问题:
1.使用字符组代替分支条件
如 [a-d] 替换(a|b|c|d)
2.优先最左匹配
如用分支条件(你好|hi|hello)预测匹配量大的词放在最左边,NFA引擎来说,因为引擎一旦找到匹配结果就会停下来,就不用回溯
3. 标准量词匹配有限
若用量词约束某个表达式,那么在匹配成功前,进行的尝试次数有下限和上限。
4.谨慎用点号元字符,尽可能不用星号和加号这样的任意量词
只要能确定范围(eg.“w”),就不要用点号;只要能够预测重复次数,就不要用量词。
捕获型括号:(...) 1 2...
仅分组的括号:(?:...)
固化分组:(?>...) 匹配规则与普通括号一样,唯一的区别就是,当此部分表达式匹配完毕,开始匹配括号外面的部分时,括号内的所有备用状态都会被放弃。也就是不会获取分组,不能在正则中反向引用
多选结构:|
匹配优先量词:* + ? {n} {m,n} {m,}
忽略优先量词:*? +? ?? {n}? {n,}? {m,n}?
占有优先量词:*+ ++ ?+ {n}+ {n,}+ {m,n}+