零宽断言
无论是零宽还是断言。听起来都是古古怪怪的,先解释下这两个名词。
- 零宽:就是没有宽度,在正则中,断言只是匹配位置,不占字符,也就是说,匹配结果是不会返回断言本身的。
- 断言:就是“我断定什么”,在正则中可以指明在指定内容的前面或者后面会出现指定规则的内容。
假如我们要爬虫抓取CSDN里文章的阅读数量。通过查看源代码可以看到这样的结构。
"<span class="read-count">阅读数:641</span>"
也就是641这个数字,那用正则怎么获取这个数字呢,正则应该怎么匹配呢?
- 正向先行断言
语法:(?=pattern)
作用:匹配pattern表达式前面内容,不返回本身
好吧,回归那个列子,要取到阅读量,在正则表达式中就意味着要匹配到</span>前面的数字内容,那么可以这样写 (?=</span>) 就可以匹配到前面的内容了。
String regex = ".+(?=</span>)"; String text = "<span class=\"read-count\">阅读数:641</span>"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(text); while (matcher.find()) { System.out.println("匹配全部结果:" + matcher.group()); } // 匹配全部结果:<span class="read-count">阅读数:641
String regex = "\\d+(?=</span>)"; String text = "<span class=\"read-count\">阅读数:641</span>"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(text); while (matcher.find()) { System.out.println("匹配数字:" + matcher.group()); } // 匹配数字:641
- 正向后行断言
语法:(?<=pattern)
作用:匹配pattern表达式后面的内容,不返回本身
正向先行是匹配前面的内容,那么正向后行就是匹配后面的内容了。上面的例子可以用正向后行处理。
String regex = "(?<=<span class=\\\"read-count\\\">阅读数:)\\d+"; String text = "<span class=\"read-count\">阅读数:641</span>"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(text); while (matcher.find()) { System.out.println("匹配数字:" + matcher.group()); } // 匹配数字:641
- 负向先行断言
语法:(?!pattern)
作用:匹配非表达式前面的内容,不返回本身
有正向就有负向,这里的负向是非的意思。
举个例子:比如有一句话"我爱祖国,我是祖国的花朵",现在要找到不是“的花朵”前面的祖国,现在可以这样写 "祖国(?!的花朵)"
String regex = "祖国(?!的花朵)"; String text = "我爱祖国,我是祖国的花朵"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(text); while (matcher.find()) { System.out.println("匹配字符串:" + matcher.group()); } // 匹配字符串:祖国
- 负向后行断言
语法:(?<!pattern)
作用:匹配非pattern表达式的后面内容,不返回本身