基础准备
正则提取代码示例:
public static String regexpExtract(String str, String regex) {
if (str == null || regex == null) {
return "";
}
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {
int n = matcher.groupCount();
for (int i = 1; i <= n; i++) {
String val = matcher.group(i);
if(val!=null){
return matcher.group(i);
}
}
}
return "";
}
零宽断言
零宽断言,大多地方这样定义它,用于查找在某些内容(但并不包括这些内容)之前或之后的东西。
我的理解是在一个限定位置的字符串之前或之后进行匹配查找。
所以零宽断言,执行过程分两种情况,如果是正向断言,应该是这样的,第一步,判断判断断言是否为真(即是否满足一定条件)第二步,如果满足条件,则进行下一步查找匹配。如果是反向断言,第一步还是按照正则表达式顺序去匹配。第二步,遇到反向代言,判断是否满足反之代言。
可以用领宽断言实现逻辑and
零宽断言有四类,它不匹配字符,只匹配一个位置,这和\b很像。用于断言后面的内容。
零宽度正预测先行断言
(?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc。
零宽度正回顾后发断言
(?<=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。
零宽度负预测先行断言
零宽度负预测先行断言(?!exp),断言此位置的后面不能匹配表达式exp。例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。
零宽度负回顾后发断言
同理,我们可以用(?<!exp),零宽度负回顾后发断言来断言此位置的前面不能匹配表达式exp:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。
零宽断言 | (?=exp) | 匹配exp前面的位置 |
---|---|---|
(?<=exp) | 匹配exp后面的位置 | |
(?!exp) | 匹配后面跟的不是exp的位置 | |
(?<!exp) | 匹配前面不是exp的位置 |
示例:
前后同时使用
str="教师14(0014)"
regex="(?<=\\()(.+?)(?=\\))";
不讲先后顺序匹配
应用场景就是,已知字符串中包含x,y,z三个词语,但是不确定顺序,需要同时将这三个词匹配出来。一般使用 (?=.*x)(?=.*y)(?=.*z) 这种断言。
1.不讲顺序提取出url的请求值
不讲先后顺序匹配字符串:此处中serialid和cityid的匹配不讲先后顺序
regex=regex : ".*api\\.app\\.yiche\\.com/webapi/api\\.ashx.*(?=.*?serialid=)(?=.*?cityid=).*"
2.不考虑先后顺序,提取出包含组合关键词所在的句子
分析:先判定整句,前后都不是整句断句标识的就判断是整句,用[^.^。^!^!]*
捕捉的关键词不讲顺序,用 (?=.*x)(?=.*y)模式匹配。
不同之处是断言内部关键词前,不能是整句标识,这样才能得到匹配结果。
String keywords="(?=[^.^。^!^!]*北京冬奥会)(?=[^.^。^!^!]*西班牙)"; String reg="([^.^。^!^!]*"+keywords+"[^.^。^!^!]*)";
来源
不捕捉模式
也可以将零宽断言理解为不捕捉模式的应用。
如何关闭圆括号的捕获能力?而只是用它来做分组,方法是在左括号的后边加上:?,这里第一个圆括弧只是用来分组,而不会占用捕获变量,所以$1的内容只能是steak或者burger,而永远不可能是bronto。
while(<>){
if(/(?:bronto)(steak|burger)/){
print "Fred wants a $1\n" ;
}
}
遇见功能,"?=",意识说目标串中肯定存在什么
str="ab4";
reg=/ab(?=\d)
"?!",意思说目标串中不应该存在什么
str="ab1";
reg=/ab(?!\d)
性能提高
来源:
问号的四种用法
1.原文符号
2.有无量词
3..非贪婪匹配
贪婪匹配
在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
非贪婪匹配
在满足匹配时,匹配尽可能短的字符串,使用?来表示非贪婪匹配
几个非场景的非贪婪pattern
4.不捕捉模式
如何关闭圆括号的捕获能力?而只是用它来做分组,方法是在左括号的后边加上:?
替换功能
//希望将字符串中的数字包裹进[]中 String str="dasfdab123adfbad124"; String reg=""; String str2 = str.replaceAll("\\d+", "[$0]"); System.out.println(str2);
结果是:dasfdab[123]adfbad[124]
多组正则合并
示例:希望从以下四种url中提出出用户id
https://weibo.com/7362321881
https://weibo.com/u/7362321881
https://weibo.com/n/我泪水是无底深海对你的爱已无言
https://weibo.com/polishembassy
如果用断言的话,相互之间的提取正则会影响,需要合并多组正则,用|串起来,才能确保满足所有条件
public class RegTest {
public static void main(String[] args) {
String reg="weibo.com/n/([^/]+)|weibo.com/(\\d+)|weibo.com/u/(\\d+)|weibo.com(?!/n/)(?!/u/)/(\\w+)";
// str="https://weibo.com/polishembassy";
// str="https://weibo.com/7362321881";
// str="https://weibo.com/u/7362321881";
str="https://weibo.com/n/我泪水是无底深海对你的爱已无言";
String result = StrUtils.regexpExtract(str, reg);
System.out.println("result = " + result);
}
}