正则表达式匹配的贪婪问题
起因
之前在研究正则表达式去匹配ip地址的时候发现它存在一个贪婪问题(要尽可能多的匹配长的位数)
问题的思考
贪婪:就是要越多(长)越好
非贪婪:越少(短)越好
简单案例(贪婪)
案例1
假如说我目前的问题是为了 匹配0-99的数字:
然后我们写出正则表达式:(完全不考虑规则问题): \d{1,2} 表示数字0-9 匹配至少1次至多2次
但是运行出来的结果:
上面这个从结果可以看出 首先 12 它没有将这个数字给拆开进行匹配,而是把它当做了一个整体,这就是一种贪婪 因为我的规则里面写的是0-9的数字匹配1-2次 它会优先考虑两次
再比如上面后面匹配的431 它就将它拆为了43 和 1 却没有将它拆解为[4,3,1]或者[4,31] 因为2是它能匹配的最大的次数,它要贪婪就要优先匹配最大的次数 也就是两次
关于 | (或)号左右的先后问题 (人为控制是否贪婪)
假如说现在:我要匹配 0-99的数字
我们将正则表达式写成这样:[0-9]|[1-9]\d
看样子似乎是将0-99的数值范围都涵盖了,但我们实际匹配起来
显然结果没有get到我输入的测试用例的意思 我输入的12 和 99明显是想要表达一个二位数的整数,但是它却将我的整数给拆分为了个位数,这儿我们犯了一个简单的错误,就是关于 | 这个符号 它的左边一旦满足了之后就已经完成了正则表达的匹配就不会考虑 右边的情况,所以我们在构建正则表达式的时候应该将数值大的数放在 | 的左边(这就是贪婪,你要非贪婪匹配到一个就行的话,就把小的放在左边) 这就是一个优先匹配的问题,看你是想优先匹配到数值小的数就结束匹配还是先匹配到数值大的数才结束匹配
改为:[1-9]\d|[0-9]
java中matcher的三种匹配方式:
matches、find、lookingAt三种:
- matcher.matches() 这个属于整个匹配,只有整个字符序列完全匹配成功才能返回True,否则返回false (多一个空格都不行)在“字符串”.matches(“正则表达式”)的方式相同均是全部匹配,有一个字符不满足都不行
比如:“1234 ”用”\d” 和”\d{4}”去匹配都不会满足,4后面有一个空格 但若是“1234”用”\d”和“\d{4}进行matches()去匹配的话 只有”\d{4}能匹配成功” 也就是上面所说的完全匹配
匹配结束后会直接返回一个true或者false
下面两个均为部分匹配:
- matcher.find()部分匹配,从当前位置开始匹配,找到一个匹配的子串,将移动下次开始匹配的位置至匹配到的子串的结尾处,
所以可以通过这种方式进行遍历一个字符的所有匹配到的字符串:
通过while和find的返回值进行循环遍历至匹配完这个字符串
Pattern p = Pattern.compile(zz_rules);
List<String> result = new ArrayList<>();
Matcher m = p.matcher(ip);//进行匹配
while (m.find()) {//判断正则表达式是否匹配到
String part = m.group();//通过group来获取每个分组的值,group(0)代表正则表达式匹配到的所有内容,1代表第一个分组
result.add(part);
System.out.println(result);
}
- matcher.lookingAt()总是从第一个字符 进行匹配,不管成功与否均不再进行匹配 返回true或false
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("22bb23");
System.out.println(m.lookingAt());// 返回true,因为\d+匹配到了前面的22
m = p.matcher("aa2223");
System.out.println(m.lookingAt());// 返回false,因为\d+不能匹配前面的aa
相比上面的find方法最主要的区别是 find在匹配字符串时,前面有不匹配的字符串能够跳过主动找寻下一个至能匹配的字符串 直到找完字符串都没找到才返回false,而lookingAt从第一个字母开始 只要不满足就返回false
就比如用”\d+”去匹配“fa 12”的话lookingAt的方式是匹配不到的,在一开始遇到f时就结束了匹配,而使用find()去找时 就能得到一个12的匹配结果,这也就是他俩最大的不同
常规的贪婪和非贪婪
正则表达式默认匹配方式为贪婪匹配,例如用*、+ 或 ? 进行不确定匹配,函数将会尽最大可能匹配尽可能长的字符串,但有时我们只想让其匹配最小范围的字串,这需要在*、+ 或 ?后加一个问号,表示把贪婪匹配转换为“非贪心”表达式或者最小匹配。
例如:要匹配 “2fd34 5421” 使用正则“\d+”和“\d+?”匹配到的结果分别为
[2,34,5421]和[2,3,4,5,4,2,1]
留言:
到这儿就结束了,本文主要是因为上一篇文章正则表达式突然认识到这个问题 所以来通过一些案例来讲解一下常见的几种贪婪的情况以及使用matcher的几种匹配模式
————C is coming
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/114553.html