很长一段时间没有写东西了,也不知道自己在忙什么,趁着今天有时间,分享一下最近学到的几个关于正则表达式的东东。
其实,关于正则表达式,前面我已经分享过几篇零基础入门正则表达式的短文,感兴趣的可以去考古一下,传送门。
之所以今天还是分享正则表达式的内容是因为今天的内容相对是正则表达式中比较难理解的一些概念,而且在最近的工作中我发现,之前学习(分享)的内容还不足以处理我现在遇到的问题,所以就有了今天的收获,希望给耐心看完的你带来一点小小的收获。闲话少说,我们直接进入正题。
还是先来看一个题目:
开发中经常遇到的一个需求,校验用户输入密码的强度,例如要求用户输入的内容至少包含 8-16 个字符,至少包含一个大写字母,一个小写字母和一个数字。
这是一个很常见的需求,但是使用我之前分享的正则的知识好像并不是那么好处理,这时就需要我们今天的主角闪亮登场了。
看到这个名词其实是有一点懵的,包括现在的我还有一点懵(因为正则这个东西,工作中用到的地方说多不多,说少不少,当时理解的东西一段时间不适用就又还给了老师),所以我今天按我自己的理解来讲,有不足火理解错误的地方还请大家不吝赐教。
零宽断言,用于查找在某些内容之前或之后的东西,用于指定一个位置,这个位置应该满足一定的条件(即断言),因为匹配的是存不存在这样一个位置,它的结果是不包含匹配的具体字符的,因此它们也被称为零宽断言。
零宽断言分为 4 种,这里就不介绍那些什么正向先行断言、负向先行断言(主要因为我也分不太清…)。其实就一句话,零宽断言 主要用于判断在被匹配的内容中是否可以找到一个前面火后面是或者不是某个内容(正则表达式)的位置。
是不是还是有点懵?懵就对了,因为这本来就是正则中相对较难理解的内容,接下来我挨个说明:
基本语法如下:(?=正则表达式)
什么意思?(?=正则表达式) 用于匹配被匹配的内容中是否存在一个位置它后面的内容满足这个正则表达式。
看例子:
I found that the flower was for you.
这里要匹配到 for 中的 fo 而不匹配 found 中的 fo
我们可以使用之前的知识来完成这个需求:
fo(\w)\b
当然也可以用我们今天提到的零宽断言来完成:
fo(?=r) ,该表达式限定了 fo 右边的位置,这个位置之后是 r。
基本语法如下:(?!正则表达式)
什么意思?(?!正则表达式) 用于匹配被匹配的内容中是否存在一个位置它后面的内容不满足这个正则表达式。
还是上面的例子,这次我要匹配 foound 中的 fo 而不匹配 for 中的 fo
可以使用如下表达式:
fo(?!r),该表达式限定了 fo 右边的位置,这个位置之后不是 r。
基本语法如下:(?<=正则表达式)
什么意思?(?<=正则表达式) 用于匹配被匹配的内容中是否存在一个位置它前面的内容满足这个正则表达式。
看一个例子:
I spend $10 for 50 oranges, $2 for 10 banana.
要求:匹配出上面内容中的价格。
当然,你可以使用以前的内容来完成这个要求,
匹配价格:\$(\d+)
那么套用刚刚学到的东西,匹配价格其实就是要匹配一个数字它前面是 $ 符号,于是就有了匹配价格的正则:(?<=\$)\d+
基本语法如下:(?<!正则表达式)
什么意思?(? 用于匹配被匹配的内容中是否存在一个位置它前面的内容不满足这个正则表达式。
还是拿上面的例子,这次匹配数量:
可以使用这个正则匹配数量:\s+(\d+)\s+,
当然使用我们刚刚学习的内容来处理也很简单,匹配前面不是紧跟 $ 符号的数字即可,于是对应的正则表达式也就出来了:\b(?
正则表达式的几种零宽断言也就介绍完毕了,需要多看多用才能灵活理解,接下来回到之前的提到的验证密码强度的例子,我们试着用今天学习的内容来完成这个例子:
(?=^.{8,16}$)(?=.*\d+.*)(?=.*[A-Z]+.*)(?=.*[a-z]+.*)(?=^.{8,16}$)(?=.*\d+.*)(?=.*[A-Z]+.*)(?=.*[a-z]+.*)另外零宽断言是一种零宽度的匹配,它匹配到的内容不会保存到匹配结果中去,这时如果想要拿到匹配到的字符串,可以在最后加一个(.*) 即可。
这时 (?=^.{8,16}$)(?=.*\d+.*)(?=.*[A-Z]+.*)(?=.*[a-z]+.*)(.*) 如果满足正则表达式我们可以通过 group 1 来获取匹配到的结果。
再看一个例子:
给定一个数字,给这个数字加上千字符,例如 给到数字 1234567 ,经过处理以后的数字是 1,234,567。
这个题也是一个比较典型的需要用到正则的断言的,我们需要匹配到哪些需要加上,的位置。
首先需要的是3个数字一组,于是很简单就能写出下面的表达式:\d{3},这时就该我们的断言出场了,(?=\d{3},又因为这3个一组的数字至少有1组,于是将表达式改为 (?=(\d{3})+$),并且这个位置不能包含左边开始的位置,因此加上(?!^),最终我们就得到了完整的表达式(?!^)(?=(\d{3})+$),可以使用代码测试一下,这里使用 java 代码
public static void main(String[] args) {
String regex = "(?!^)(?=(\\d{3})+$)";
String num = "1234567";
String s = num.replaceAll(regex, ",");
System.out.println(s);
}
结果:1,234,567
希望对看完的你有帮助,由于水平有限,如果有不正确的地方也欢迎大家积极指正。
好了,今天的内容就分享到这里了,以后遇到有趣的相关内容再分享出来。