Java – 正则表达式
简介
本文讲解Java 中正则表达式的使用和注意事项
正则表达式可以校验字符串是否满足一定的规则,并用来校验数据格式的合法性。
本篇文章中分别使用正则表达式进行文本判断,和信息提取。
正则表达式基本规则
单个字符匹配规则表
表达 | 说明 | 举例 | 结果 |
---|---|---|---|
[abc] | 在单个字符上匹配中括号内的字符 | [abc] | 只能是a,b或c |
[^] | 在单个字符上匹配中除括号内的字符 | [^abc] | 不能是a,b或c |
[a-zA-Z] | a到z,A到Z | [a-zA-Z] | a-Z 都可匹配 |
[a-d[m-p]] | a到d,或m-p都可被匹配 | [a-d[m-p]] | a到d,或m-p |
[a-z&&[def]] | a-z中和d,e,f的交集 | [a-z&&[def]] | def |
[a-z&&[^bc]] | a-z中不是b和c的字母 | [a-z&&[^bc]] | ad-z |
[a-z&&[^m-p]] | a-z中除了m到p的交集 | [a-z&&[^m-p]] | [a-lq-z] |
预定义字符规则表
表达 | 说明 | 举例 | 结果 |
---|---|---|---|
. | 任意字符,不包括回车 \n | . | a-Z0-9!-) |
[] | 里面的内容匹配一次,可配合数量词定位数量 | [0-9] | 0123456789 |
() | 分组 | a(bc)+ | abcbcbcbc都可以 |
^ | 取反 | ^a | 除a以外都可以 |
&& | 交集,不能写单个&,否则会被认为是普通字母 & | abc&&b | abc中要和b一样的=>结果b |
| | 写在方括号外面表示并集(或) | x|X | x和X都可以 |
\ | 转义字符 | \\ | =>\ |
(?i) | 字母不分大小写 | (?i)abc
a((?i)b)c |
abc,Abc,ABc,ABC,AbC,aBc等都可以
只能允许b可以大小写不分 |
\d | 一个数字 | \d | 0-9 |
\D | 非数字 | \D | 不是数字都可以 |
\s | 一个空白字符 | \s | [\t\n\x0B\f\r] |
\S | 非空白字符 | \S | [^\s] |
\w | [a-zA-Z0-9_] 英文、数字、下划线 | \w | a-z,A-Z,0-9,和_ |
\W | 和[^a-zA-Z0-9_],非英文、非数字、非下划线 | \W | [^\w] |
数量词规则
表达 | 说明 | 举例 | 结果 |
---|---|---|---|
? | 一次或0次 | [a]. | a不出现或出现1次 |
* | 0次或多次 | [a]* | a不出现或出现多次 |
+ | 一次或多次 | [a]+ | a至少出现一次,也可出现多次 |
{n} | 正好n次 | [a]{3} | a正好出现3次 |
{n,} | 至少n次以上 | [a]{2,} | a至少出现2次以上 |
{n,m} | 至少n次以上,m次以下 | [a]{2,5} | a到少出现2次,但不超过5次 |
String 类相关正则方法
matches 正则判断
在String 实例中,有一个方法 matches(String regex) , 可以传入正则表达式字符串来判断这个String实例中是否符合正则规则,如果符合返回 true , 否则返回 false
String a = "abcdefg";
boolean matches = a.matches("\\w+");
System.out.println(matches); // => true \\w指 a-zA-Z0-9_,字符串中 a 包含这些字母
String a = "abcdefg";
boolean matches = a.matches("\\d+");
System.out.println(matches); // => false \\d 表示 0-9,而a字符串中并没有数字0-9
replaceAll() 使用正则方法替换
String 类中提供一个文本替换的功能,且这个替换功能支持正则表达式
String s = "用户名aaaa密码aaaa性别"
s.replaceAll("a+","替换文本");
split() 使用正则方法分割文本
String 类中提供一个文本分割的功能,且这个分割功能支持正则表达式
String s = "用户名aaaa密码aaaa性别"
s.split("a+"); // => {用户名,密码,性别}
Pattern 和 Matcher
通过使用Pattern类来进行匹配,再使用Matcher来进行取值。
Pattern是管理正则表达式的类,用它来生成一个带有正则表达式的对象
Matcher是一个文本匹配器,作用是按照正则表达式对象的规则去读取字符串,Java默认从头开始读取。
创建Pattern正则对象
创建Pattern正则对象不需要使用 new,只需要调用静态方法 compile 方法就可以了,并传入正则字符串
Pattern compile = Pattern.compile("\\w+");
创建Matcher文本匹配器
Matcher文本匹配器在匹配字串时需要提供正则对象,上面我们通过 Pattern.compile("\\w+"); 申请了一个正则对象,接下来可以使用Matcher文本匹配器匹配我们想要的字符串
String a = "abcdefghijklmn";
Matcher m = p.matcher( str )
通过调用正则对象的 matcher 方法取得 Matcher 对象
find() 查找符合字串
通过调用Matcher 实例对象的 find() 方法,指向字串中的匹配项,若找到匹配项,返回 true,每调用一次,则在上一次匹配的位置上,继续往下寻找匹配,直至找不到为止,则返回false
boolean isFind = m.find(); // => 如果找到返回 true , 否则返回 false
在底层中,届果 find() 找到的话,会记录该匹配项的起始索引和结束索引+1,因为 substring() 方法中,就是取出起始索引和结束索引+1的位置文本。
group() 取得匹配字串
find() 方法让我们能在字符串中找到匹配项的位置,而group() 方法,则是取出字符串中匹配的文本。
通过调用 Matcher 对象的group() 方法即可拿到当前 find() 方法寻找到的匹配项。
String str = m.group();
通过循环匹配所有项
Pattern compile = Pattern.compile("\\w+");
Matcher m = compile.matcher(string );
while (m.find()){
System.out.println(m.group());
}
贪婪爬取
贪婪爬取指的是,希望能多匹配一些的话就多匹配一些,举例子
String s = "abbbbbbbbbbbccccccccccc"
使用 ab+ 规则取出匹配项
如果使用贪婪爬取,那么我们最后得到的结果是
“abbbbbbbbbbb”
Java默认使用的是贪婪爬取,其正则如下(省略Pattern操作)
String s = "abbbbbbbbbbbccccccccccc"
String regex = "ab+"
非贪婪爬取
非贪婪爬取和贪婪爬取刚好相反,也就是说,当Java找到适合的匹配后,就停止继续匹配了,举
String s = "abbbbbbbbbbbccccccccccc"
使用 ab+ 规则取出匹配项(非贪婪爬取)
如果使用非贪婪爬取,那么我们最后得到的结果是
“ab”
如果我们需要使用 非贪婪爬取,我们只需要在正则规则+,* 之类的数量词后面加 "?
",如下(省略Pattern操作)
String s = "abbbbbbbbbbbccccccccccc"
String regex = "ab+?"
匹配分组
捕获分组
假如我们需要使用定义过的正则表达式时,我们可以通过调用分组的方式复用之前定义过的正则。
分组使用小括号定义。
规则
1.从1开始,连续不间断
2.以左括号为基准,最左边的是第一组,其次为第二组,以此类推
(\\d+)(\\w+)(\\s+);
// => 第一组为 (\\d+)
// => 第二组为 (\\w+)
// => 第三组为 (\\s+)
(\\d+(\\w+))(\\s+)
// => 第一组为 (\\d+(\\w+))
// => 第二组为 (\\w+)
// => 第三组为 (\\s+)
举例,
匹配 aaa123aaa , bb445bb , &467&
我们知道,上面三个的规律是,前后是一样的,前面的字母匹配,我们可以使用 (.+) 就能把 aaa, bb, & 给匹配上了,因为我们做了分组,所以这里的 (.+) 是一组,我们可以通过使用 \\1 来取得这一组的定义,如下
String regex = "(.+).+\\1"
(.+) 开头有多个任意字符,并设为一个分组
.+ 中间有一个或多个任意字符
\\1 调用第一个分组的定义,也就是 (.+)
我们再来举一个例子:
String regex = "((.)\\2*).+\\1"
(.)
指的是有一个任意字符
\\2
在此列中,因为 (.) 在另一个括号内,因此它是第2组了,所以 \\2 指的是 (.)
*
作用于 \\2 表示 \\2 有0或多个
((.)\\2*)
表示 (.) 作为一个组,且组在第二组,并且认为这个组中有0到多个
.+
中间的任意字符
\\1
调用第一组,即 ((.)\\2*)
外部使用分组
内部使用分组时,我们使用 \\ 号进行调用,而如果需要在外部调用分组的话,我们可以使用 $ 符调用就可
String s = "aaabbbbbbbbcdddd"
s.replaceAll("(.)\\1+", "$1" );
// => 会匹配出四个项 [aaa],[bbbbbbbb],[c],[dddd]
// => 最后会把 aaa->a, bbbbbbbb->b, c->c, dddd->d
// => abcd
(.)\\1+
表示有一个或多个第一组的任意字符定义
$1
表示在外部使用 (.)
非捕获分组
当我们使用捕获分组时,我们需要使用 () 来进行分组,但是有时候我们需要 () 并不是因为我们需要分组,而仅仅只是缩小匹配范围,如
[(a|b)(c|d)] 这里的(a|b)仅仅是为了缩小到a或b的匹配,如果不加 () ,那么 | 号或会以全局的方式进行匹配,但加了 () 后, (a|b) 则占用了一个分组,而我们并不想它占用分组名额时,我们可以使用非捕获分组定义,定义如下
表达 | 说明 | 举例 | 结果 |
---|---|---|---|
(?:正则) | 获取所有 | Java(?:8|11|17) | Java8,Java11,Java17 |
(?=正则) | 获取前面部分 | Java(?=8|11|17) | Java,Java,Java |
(?!正则) | 获取不是指定内容的前面部分 | Java(?!8|11|17) | 8,11,17 |
共有 0 条评论