文章目录
- 正则式 a?
- 正则式 ^\w+\d
- 正则式 (\d){4}|\1{2}
- 正则式 \d{4}|\d{2}
正则式 a?
正则式:a?
被匹配的字符串:a<>aava</>ab
看下面的 Java 代码:
String test = "a<>aava</>abb";
String reg = "a?";
System.out.println(test.replaceAll(reg, "#"));
输出的结果是:
##<#>###v##<#/#>##b#b#
解读下匹配过程:
正则式 a?
,是表示匹配一个 a 或者 0 个 a, 没有 a 也算匹配成功。首先匹配 a<>aava</>abb
的字符“a”,整个正则式匹配成功第 1 次,替换成 #
,接着匹配第 2 个字符“<”,不是字符“a”,匹配字符失败,而正则式可以匹配 0 个 a,所以会匹配字符“<”前面的位置,所以整个正则式匹配成功第 2 次(即第 2 次迭代匹配成功),我晕这样也行!所以在字符“<” 前再插入第 2 个 #
,后面也是依照这样奇葩的逻辑去匹配替换。
正则式 ^\w+\d
正则式:^\w+\d
被匹配的字符串:1a2b2c2de
String test = "1a2b2c2de";
String test1 = "%1a2b2c2de"
String reg = "^\\w+\\d"; // 在 Java中,正则表达式引擎认为 \ 是普通的字符,\\ 才是转义符号
System.out.println("结果1:"+test.replaceAll(reg, "#"));
System.out.println("结果2:"+test1.replaceAll(reg, "#"));
输出结果:
结果1:#de
结果2:%1a2b2c2de
匹配过程解读:
^
是一个虚拟的概念,表示字符串第 1 个字符的前面,字符串第 1 个字符前面有东西吗?没有吧,所以是一个虚拟的概念。而这个 ^
字符告诉了正则表达式引擎要查找紧跟在头部后面且符合正则式的字符串。
我们看到 ^
后面跟着 \w+
,而 \w
表示英文字母和阿拉伯数字中的任意一个字符,+
则表示前面的子表达式 1 个或者多个,综合起来的含义就是 1 个或者多个英文字母和(或)数字。所以 ^\w+
的含义是指紧跟在头部后面的 1 个或者多个英文字母和(或)数字。再看看正则式,后面还跟着一个 \d
,它代表匹配任意一个阿拉伯数字,所以整个正则表达式的含义是指紧跟在头部后面的以 1 个或者多个英文字母和(或)数字组成的,且以数字为结尾的字符串。
我们看到字符串 %1a2b2c2de
查找不到符合正则式 ^\w+\d
的字符串,所以没有替换,直接输出原来的字符串,为什么?正则式要查找的是跟在头部后面的且满足正则式的字符串,现在跟在头部后面的是 %,不满足 \w
这个表达式,而 1a2b2c2
虽然满足 \w+\d
,但是它并不是紧跟在头部 ^
的后面,它是紧跟在 %
的后面,所以结果 2 输出原来的字符串。
正则式 (\d){4}|\1{2}
console.log("1234567890".match(/(\d){4}|\1{2}/g)); // ["1234", "5678", "", "", ""]
输出的结果:
["1234", "5678", "", "", ""]
关于“或者”的正则表达式中,第 1 个表达式 (\d){4}
匹配成功,第 2 个表达式 \1{2}
就不会去匹配了,只有第 1 个匹配失败,才会让第 2 个去匹配。
修饰符g表示全文查找,因此前两次匹配到了 “1234” 和 “5678”,此时正则引擎的指针处于数字 8 的后面,后面的字符显然子表达式 (\d){4}
无法匹配了,此时第一个捕获组 (\d)
匹配到内容为空,那么反向引用 \1
将指向空字符串,\1{2}
也就是一个空白字符串,后面可以匹配到 8、9、0 后面共 3 个位置,故最终又匹配到三个空字符串。
正则式 \d{4}|\d{2}
"1234567890".match(/\d{4}|\d{2}/g);
输出结果为:
["1234", "5678", "90"]
\d{4}
匹配4个任意数字成功后,\d{2}
就不会匹配了,直到后面匹配 “90” 失败了,才让 \d{2}
去匹配,结果匹配成功了,字符串也到结尾了,所以最终成功匹配的结果有三个字符串。