基本介绍
首先我们需要了解的是正则表达式中的各种元字符的功能,主要分为以下几种:
- 限定符
- 选择匹配符
- 分组组合和反向引用符
- 特殊字符
- 字符匹配符
- 定位符
需要注意的是:在 Java正则表达式中,两个斜杠 \\ 相当于其它语言中的一个斜杠 \ 。
字符匹配符
符号 | 含义 | 示例 | 解释 |
[ ] | 可以匹配的字符列表 | [abcjs] | a、b、c、j、s都可以匹配到 |
[^] | 不可以被匹配的字符列表 | [^abc] | a、b、c不可以被匹配 |
- | 连字符 | a-z | 可以匹配任意a到z的字母 |
. | 匹配除 \n 之外的任何字符 | a..b | 以a开头b结尾的字符串,中包括任意两个字符 |
\\d | 匹配单个数字字符 | \\d{3}(\\d)? | 匹配连续3个或4个数字的字符串 |
\\D | 匹配非数字字符 | \\D(\\d)* | 以单个非数字字符开头,后面接任意个数字的字符串 |
\\w | 匹配单个数字、英文字符、下划线 | \\d{3}\\w{4} | 以3个数字字符开头的长度为7的数字字母字符串 |
\\W | 匹配单个非数字、非英文字符、非下划线 | \\W+\\d{2} | 以至少一个非数字字母字符开头,两个数字字符结尾的字符串 |
\\s | 匹配任何空白字符(空格,制表符等) | ||
\\S | 匹配任何非空白字符,和\s刚好相反 |
选择匹配符
符号 | 含义 | 示例 | 解释 |
| | 或者的意思 | ab|cd | 匹配ab或者cd |
用于在匹配时有选择的降低匹配标准。
限定符
用于指定其前面的字符和组合项连续出现多少次
符号 | 含义 | 示例 | 说明 | 示例 |
* | 重复0次或n次 | (abc)* | 以abc开头的,子串只包含abc的字符串 | abc,abcabc |
+ | 重复1次或多次 | (abc)+ | 至少以1个abc开头,子串只包含abc的字符串 | abc,abcabc |
? | 重复0次或1次 | (abc)? | 以abc开头的字符串 | abc |
{n} | 限定只能出现n次 | [a-d]{3} | 由连续的 a、b、c、d组成的字符串中任意长度为3子串 |
定位符
规定要匹配的字符在字符串中出现的位置,比如是在字符串开始还是在结束处。
符号 | 含义 |
^ | 开头 |
$ | 结尾 |
\\b | 匹配目标字符串的边界,子串之间的空格 |
\B | 匹配字符的非边界 |
这里主要演示一下 \\b 和 \\B :
public static void main(String[] args) { String content = "我爱学习 学习不爱我 学习很快乐"; String regex = "学习\\B"; Pattern compile = Pattern.compile(regex); Matcher matcher = compile.matcher(content); while (matcher.find()){ System.out.println(matcher.group()); } }
当我们设置匹配语句为 \\b 的时候,输出结果:
学习
当我们设置匹配语句为 \\B 的时候,输出结果:
学习 学习
可以看到,\\b 匹配的是子串"学习"后是空格的,而 \\B 刚好相反。
分组
捕获分组
我们上一篇博客写过分组的案例,也就是 group(0),group(1)这种,也叫做非命名捕获。
这里主要介绍一种新的分组方法,叫做命名捕获,也就是说我们可以自定义组的名字。相比较之前的哪一种,它既可以使用非命名捕获(通过组号获取匹配的子串),也可以通过自定义的名字来捕获。
语法:<?<name><pattern>>
其中,需要先写一个问号?,<name>是我们对组的命名,不要太离谱就行;<pattern>是我们的正则表达式,和非命名捕获是一样的。
String content = "sajnj ax1122s sjnaj4529 s584"; String regex = "(?<group1>\\d\\d)(?<group2>\\d\\d)"; Pattern compile = Pattern.compile(regex); Matcher matcher = compile.matcher(content); while (matcher.find()){ System.out.println(matcher.group("group1")); System.out.println(matcher.group("group2")); }
非捕获分组
Java正则表达式中的不捕获匹配(Non-capturing Group)指的是使用括号来分组匹配,但不会将该分组的匹配结果保存到匹配结果中。这样可以在正则表达式中使用括号进行逻辑分组,但不会捕获分组的内容,从而减少内存开销并提高性能。
也就是说,虽然有括号但是不算是一个组,你使用组索引 matcher.group(n) 是获取不到结果的。
String content = "industries industry"; Pattern pattern = Pattern.compile("industr(?:y|ies)"); Matcher matcher = pattern.matcher(content); while (matcher.find()){ System.out.println(matcher.group(0)); }
输出:
industries industry
正向预查
String content = "My operating system is Windows 11,his operating system is Windows XP"; Pattern pattern = Pattern.compile("Windows (?=11|XP)"); Matcher matcher = pattern.matcher(content); while (matcher.find()){ System.out.println(matcher.group(0)); }
运行结果:
Windows Windows
调试正则表达式后,发现 (?=pattern)这种非捕获分组,它必须满足括号后面的条件才能被匹配,但是比如"Windows (?=11|XP)",要被匹配到的只可能是 "Windows 11" 或者 "Windows XP",但是这里的"11"和"XP"不会被保存到结果。
负向预查
String content = "My operating system is Windows 11,his operating system is Windows XP"; Pattern pattern = Pattern.compile("Windows (?!8|9|10)"); Matcher matcher = pattern.matcher(content); while (matcher.find()){ System.out.println(matcher.group(0)); }
运行结果:
Windows Windows
调试正则表达式后,发现 (?!pattern)这种非捕获分组,它必须满足括号后面的条件才能被匹配,但是比如"Windows (?=11|XP)",要被匹配到的只可能是除了 "Windows 11" 和 "Windows XP"之外的其他"Windows xxxx"的字符串,而且这里的"xxxx"同样不会被保存到结果。