【JavaSE】java中的正则表达式(从0到1学会正则表达式)

前言

java中的正则表达式,从认识正则表达式的常用类,底层实现原理,到元字符的使用,元字符的使用细节及注意事项,分组引用及反向引用实例,Matcher类常用的其它方法,String类中的正则使用,及常用的正则表达式(摘选),
带你从0到1学会正则表达式,一篇文章足以~

一、正则表达式的三个常用类

1.Pattern类

Pattern 对象是一个正则表达式对象。Pattern 类没有公共构造方法。需要使用 Pattern 类 compile 方法接受一个正则表达式,获得 Pattern对象

String regex = "\\d{4}"; // 正则表达式
Pattern pattern = Pattern.compile(String regex); // 接受正则表达式(字符串),构造正则表达式对象
// 匿名对象
Pattern.compile(String regex);

 

2.Matcher类

在有了正则表达式对象之后,我们需要匹配器,即 Matcher 类的对象
Matcher 对象是对输入字符串解释和匹配的引擎。Matcher 类没有公共构造方法。需要使用 Pattern 对象的 matcher 方法接受匹配的内容,获得 Matcher 对象

Matcher matcher = pattern.matcher(String content);
// 匿名对象
Pattern.compile(String regex).matcher(String content);

 

3.PatternSyntaxException类

PatternSyntaxException类是一个非强制异常类,它表示正则模式中的语法错误

 
 

二、正则表达式的底层实现

有了匹配器后,就可以进行对字符串的检索了。

String content = "1234ab123cd56789"; // 检索的内容
String regex = "\\d{4}"; // 正则表达式
Pattern pattern = Pattern.compile(regex); // 获得正则表达式对象
Matcher matcher = Pattern.matcher(content); // 获得匹配器

// 开始对字符串从头到尾进行检索
while(matcher.find()){
	// 将获取的满足的子字符串输出
	System.out.println(matcher.group());
}

/* 输出结果 */
1234
5678

1.Matcher.find()和Matcher.group()方法

下边介绍匹配器对字符串的检索时的 find() 方法和 group() 方法的底层实现

Matcher类中有两个属性: int[] groups、int oldlast
int[] gorups 在执行 find() 方法时用来存放匹配到的字符串的 开始和结束后一位下标。并在需要时通过调用 gorup() 方法来获取下标对字符串进行截取。
int oldlast 存放匹配字符结束后一位的下标,作为下一次匹配的开始位置

 

2.Matcher.find()和Matcher.group()实现过程

String content = "1234abcd5678opq";
String regex = "\\d\\d\\d\\d"; // \\d表示一位 0-9 的数字
...
// 匹配content中的四位数字
while(matcher.find()){
	// 用 group()输出匹配到的子字符串
	System.out.println(matcher.group());
}

首先,find()方法会对字符串依次进行检索,
1.如果末匹配到,返回false.结束匹配

2.如果匹配到指定规则子字符串:

如上面的例子,匹配 1234 时,会将子字符串1234(在content)中的初始位置, 也就是字符1 对应的 下标 存入 groups[0],将末尾位置 字符4 对应的 下标+1 存入到 group[1]中;
并在需要时用 group() 方法获取 匹配到的子字符串,group() 方法会返回对content字符串中groups[0]和group[1]之间的子字符串,也就是对其进行截取.
即: group() = content.subString( groups[0],gorups[1] );

同时还会记录当前匹配到的子字符中末尾后一位, 即将 groups[1] 存入到 oldlast 中 (用于下一次匹配的开始)

随后进行下一次匹配,也就是执行第二次while()循环,以 oldlast 为开始位置 往后进行匹配,同样的,在匹配到子字符串 如 5678 时,初始 字符5 对应的下标存入 groups[0],末尾 字符8 对应的下标存入到groups[1]中(此次会将上一次的匹配结果替换掉),将当前匹配到的子字符中末尾后一位存入到 oldlast 中。

当下一次匹配进行,匹配到字符串(content)的结尾,末找到指定的子字符串时,返回false,结束 while()循环

 

3.Matcher.group()方法中的参数

grop() 方法是带有参数的,如: 0,1,2,3…
group(0)获取的是 1234,即 匹配到的子字符串整体;

不带参数的group()方法其实也是默认参数为0;
源码如下:
       public String group() {
        return group(0);
       }

当我们对正则表达式进行分组时,即添加小括号,如:
       String regex = (\d\d) (\d\d);
       String content = “1234abcd”;

group(1)获取的是 整体中的第一组,也就是正则表达式中第一个括号中的内容: 12
依次的,group(2)获取第二组: 34; …

注意:如果想要获取超过范围的分组,会报错

 
 

三、正则表达式:元字符

Pattern.matches(String regex,String content);方法
用正则regex去匹配 整个 字符串content

1.字符匹配符

正则: .

. (小数点) 则表示“\n”和"\r"之外的任何单个字符

则表示任意四个字符

Pattrn.matches("....","1234");
Pattrn.matches("....","abcd");
 // true
 
Pattrn.matches("....","12345");
 // false

 

正则: \d

\d表示一个数字

aaa\d检验是否以aaa开头,且以一个数字结尾的字符串

aaa\dbbbaaa和bbb中间有一个数字

aaa\d\daaa后面跟2个数字

---
Pattrn.matches("aaa\\d","aa1"); // flase
---
Pattrn.matches("aaa\\d","aaa11"); // flase
---
Pattrn.matches("aaa\\d","aaa9") // true

注意:在Java定义的正则里,由于一个 \表示的是字符串转义,因此在Java定义带有\的元字符时,还需要多写一个 \,即 \ \,至于其他语言,自己可查阅相关资料进行了解。

 

正则: \D

\D 表示一个非数字,它和上面 \d 的意思恰好相反。

\D\D\D则表示一个长度为3,不包含数字的字符串。

Pattrn.matches("\\D\\D\\D",11); // false
Pattrn.matches("\\D\\D\\D","aaa"); // true

111\D222则表示111和222中间,必须包含一个非数字。

Pattrn.matches("111\D222","1110222"); // false
Pattrn.matches("111\D222","111+222"); // true

 

正则: \w

\w 表示一个字母(大小写均可)、数字,或下划线。

12\w45则表示12和45中间是一个字母,数字,或下划线。

Pattrn.matches("12\\w45","12345");
Pattrn.matches("12\\w45","12a45");
Pattrn.matches("12\\w45","12_45");
 // true

Pattrn.matches("12\\w45","12+45");
 // false

 

正则: \W

\W 与 \w 相反,表示这个位置的字符既不是字母、数字,也不是下划线。

也就是:特殊符号(除下划线),或者空格等满足。

12\w45则表示12和45中间是一个非字母,非数字,或非下划线。

Pattrn.matches("12\\W45","12345");
Pattrn.matches("12\\W45","12A45");
Pattrn.matches("12\\W45","12_45");
 // false

Pattrn.matches("12\\W45","12+45");
Pattrn.matches("12\\W45","12 45"); 
 // true

 

正则:[abc]

[ ] 表示匹配其中任意一个字符。

a[bcd]e则表示a和e的中间须是b,或c,或d其中的一个

Pattrn.matches("a[bcd]e","abe");
Pattrn.matches("a[bcd]e","ace");
 // true
 
Pattrn.matches("a[bcd]e","a6e");
 // false

注意:用 | 表示其中之一,他可以是字符,也可以是字符串。而只用中括号时,则只表示其中一个字符。
 

正则:[^abc]

[^abc]与 [abc] 相反,表示不与中括号里的任意字符匹配

​ a[^bcd]e:则表示a和e的中间除b,c,d这三个字符外,其他的字符都满足。

Pattrn.matches("a[\^abc]e","a1e"); // true
Pattrn.matches("a[\^abc]e","aae"); // false

 

正则:[a-z]

[值1-值2] 则表示值1到值2中间的所有字符都满足(包括值1和值2)。常用该正则来表示大小写字母范围,数字范围。

a[b-d]e等同于 a[bcd]e,因为 b-d 其实就是b,c,d三个数。

Pattrn.matches("a[b-d]e","abe"); // true
Pattrn.matches("a[b-d]e","a1e"); // false

a[0-9]e则表示ae中间是一个数字等同于 a\de(前面说过\d表示一个数字)

Pattrn.matches("a[0-9]e","ane"); // false
Pattrn.matches("a[0-9]e","a5e"); // true

 

正则:[^a-z]

与 [值1-值2] 相反,[^值1-值2] 则表示除值1和值2之外的所有字符,都可以满足。

a[^1-3]e则表示a和e中间的字符,只要不是1,2,3,则都满足。

Pattrn.matches("a[^1-3]e","a4e"); // true
Pattrn.matches("a[^1-3]e","a1e"); // false

 

2.选择匹配符

正则:|

| (竖线) 则表示或的关系,表示检测的字符串须满足其中一个时,才符合条件

aa|bb|cc则表示输入的字符串须是aa,或bb,或cc其中的一个。

Pattrn.matches("aa|bb|cc","aa");
Pattrn.matches("aa|bb|cc","bb");
Pattrn.matches("aa|bb|cc","cc");
 // true
 
Pattrn.matches("aa|bb|cc","1");
 // false

xx(aa|bb|cc)yy则表示输入的字符串须是xx开头yy结尾且中间是aa、bb或cc

Pattrn.matches("xx(aa|bb|cc)yy","xxaayy");
Pattrn.matches("xx(aa|bb|cc)yy","xxbbyy");
Pattrn.matches("xx(aa|bb|cc)yy","xxccyy");
 // true

Pattrn.matches("xx(aa|bb|cc)yy","xx11yy");
 // false

 

3.限定符

正则:*

表示匹配前面的子表达式任意次。

abc*de:**表示 ab 和 de 之间有任意个数(包括0)c **

a(bc)*de:**表示 ab 和 de 之间有任意个数(包括0)bc **

Pattrn.matches("abc*de","abde");
Pattrn.matches("abc*de","abcde");
Pattrn.matches("abc*de","abccde");
 // true
 
Pattrn.matches("abc*de","ade");
 // false

 

正则:+

匹配前面的子表达式一次或多次 (次数 >= 1,即至少1次)

abc+deab 和 de 之间至少有一个 c 。

Pattrn.matches("abc?de","abcde");
Pattrn.matches("abc?de","abccccde");
 // true
 
Pattrn.matches("abc?de","abde");
 // false

a(bc)+dea 和 de 之间至少有一个bc 。

Pattrn.matches("a(bc)?de","abcde");
Pattrn.matches("a(bc)?de","abcbcde");
 // true
 
Pattrn.matches("a(bc)?de","abde");
 // false

 

正则:?

? 表示匹配前面的子表达式零次或一次。

abc?de: 表示可匹配的字符串为 abde (匹配0次c) 或 abcde (匹配1次c)

Pattrn.matches("abc?de","abde");
Pattrn.matches("abc?de","abcde");
 // true	
 
Pattrn.matches("abc?de","ade");
 // false

 

正则:{n}

这里的 n 是一个非负整数。匹配确定的前面的子表达式 n 次。

abc{3}de表示 ab 和 de 之间有3个c。相当于abcccde

Pattrn.matches("abc{3}de","abde");
Pattrn.matches("abc{3}de","abcde");
Pattrn.matches("abc{3}de","abccde");
 // false
 
Pattrn.matches("abc{3}de","abcccde");
 // true

ab(xx|yy){3}de表示 ab 和 de 之间有 xx 或 yy 的个数, 一起合计为3个。

Pattrn.matches("ab(xx|yy){3}de","abxxxxxxde");
Pattrn.matches("ab(xx|yy){3}de","abyyyyyyde");
Pattrn.matches("ab(xx|yy){3}de","abxxyyxxde");
 // true
 
Pattrn.matches("ab(xx|yy){3}de","abcxxyyde");
 // true

 

正则:{n,}

这里的 n 是一个非负整数。指匹配的子字符串长度不小于n。

abc{3,}de表示 ab 和 de 至少有3个c。

Pattrn.matches("abc{3,}de","abde");
Pattrn.matches("abc{3,}de","abcde");
Pattrn.matches("abc{3,}de","abccde");
 // false
 
Pattrn.matches("abc{3}de","abcccde");
Pattrn.matches("abc{3}de","abccccde");
 // true

 

正则:{n,m}

m和n均为非负整数,其中 n<=m。最少匹配 n 次且最多匹配 m 次。

abc{2,3}de表示 ab 和 de 之间有 2 到 3 个 c。

Pattrn.matches("abc{2,3}de","abccde");
Pattrn.matches("abc{2,3}de","abcccde");
 // true
 
Pattrn.matches("abc{2,3}de","abcde");
 // false

4.分组和反向引用符

(Pattern)

非命名捕获,编号为 0 的第一个捕获是由整个子字符串,其它捕获结果根据 左括号 的顺序从1自动编号

如 (\\d\d)(\\d\\d) 去匹配 “abcd1234”

  • group(0) = “1234”;
  • group(1) = “12”;
  • group(2) = “34”;

 

(?<组名>Pattern)

命名捕获,即在分组的同给其命名,命名后分组可以通过gruop(name)来获取

如(?<分组1>\\d\d)(?<分组2>\\d\\d) 去匹配 “abcd1234”

  • group(0) = “1234”;
  • group(“分组1”) = “12”;
  • group(“分组2”) = “34”;
     
引用(\\n)

(内部引用)对已分组的正则表达式进行引用,(n表示一个数字)如:\\1表示第一个括号里的内容,以此类推

如正则表达式 (\\d)\\1(\\d)\\2 表示的是 第一个数字和第二个数字相同,第三个数字和第四个数字相同

  • 1122、5566 7788 等满足上式正则表达式、

 

反向引用($n)

(外部引用),与内部引用使用方法类似,只不过是在regex的外部使用

如Matcher类中的replace(String s)方法

String content = "122333444455555";
String regex = "(\\d)\\1*";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);

//	使用replaceAll方法,
//  将content中含有regex的内容全都替换成 $1,即(\\d)
String newstring = matcher.replaceAll("$1");
System.out.println(newstring);

/* newString = "12345"; */

 

5.定位符

正则: ^

^ 表示以指定的字符开头

如 ^\\d{3}+[a-z]* 去匹配:

  • a123abc,匹配不成功
  • 123abc,输出整个字符串abc
     
正则: $

与 ^ 类似,$ 则是以指定字符结尾

如 \\d{3}+[a-z]*$ 去匹配

  • a123abc6,匹配不成功
  • 123abc,输出整个字符串abc

 

关于 ^ 和 $ 的使用场景

通常,我们在使用Matcher.find()方法时,是以正则表达式String regex 去匹配String content中的子字符串,即字符串content中只要有一部分满足regex即匹配成功返回true;
当使用了 ^ 时,表示的不是字符串content中的子字符串以什么开头,而是content的开头是什么字符。$ 同样如此;下面有几个例子供大家理解:

用Matcher.find()方法,regex = “^\d{2}” 去匹配:

  • content = “abc123”; 匹配不成功,
  • content = “1abc123” 匹配不成功,
  • content = “12abc123”; 返回 “123abc123”;
    这里12a,12ab,12abc…同样满足,但是因为java匹配默认贪婪匹配.

当我们给regex正则表达式的头尾分别加上 ^ ,$ 时,此时用find()方法进行匹配不再时部分匹配,表示的是将对整个字符串content和regex进行匹配,即content == regex?

6.注意

元字符使用时的一些细节

1.连字符只能用在【】内即: 【A-Z】,在【】外面或如【a-】、【\\w-】中的边字符都只是一个普通字符
 
2.像. ? 这些字符在【】中也是一个普通字符
 
3.注意: java匹配默认贪婪匹配,即尽可能的多的,如:\d{3,} 当字符串中如:4456,会匹配 4456 而不是 445
 
4.要匹配内容中的字符 \ 时,因为 java和正则的转义,正则表达式要写为:
String regex = “\\\\” 才能将 \ 表示成一个普通字符

 
 

四、Matcher类其它常用方法

Matcher.start()

返回 gruops[0],即匹配到的子字符串初始字符下标

 

Matcher.end()

返回 gruops[1],即匹配到的子字符串末尾字符下标+1

 

Matcher.matchers()

将字符串整体与 String regex 匹配

 

Matcher.replaceAll(String s)

用 s 替换匹配到的 (regex) 内容

 
 

五、在String类的方法中使用正则表达式

更为便捷的是,String类中就有和正则表达式相关的方法
 

String.replaceAll(String regex,String s)

在String类replaceAll方法中,已经为我们创建好了匹配器,然后返回Matcher.replaceAll方法

String类中的replaceAll源码:
public String replaceAll(String regex, String replacement) {
       return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}

(Pattern.compile(String regex).matcher(String content)为Matcher类的匿名对象)

 

String.matches(String regex)

Pattern.matches方法前面在介绍正则元字符时使用过。
String.matchesPattern.matches 都是间接的使用Matcher类的matches方法

Pattern类中的matches方法源码:
public static boolean matches(String regex, CharSequence input) {
       Pattern p = Pattern.compile(regex);
       Matcher m = p.matcher(input);
        return m.matches();
}
String类中的matches方法源码:
public boolean matches(String regex) {
       return Pattern.matches(regex, this);
}

 

String.split(String regex)

使用正则表达式对字符串进行分割,例如:

content = "12-34-56+78#9";
String[] result = content.split("[-+#]");
for(String s:result){
	System.out.println(s);
}
/* 输出结果 */
12
34
56
78
9

 
 

六、最后:常用的正则表达式

校验数字的正则表达式

  • 数字:“^[0-9]$”;
  • n位的数字:“^\\d{n}$”;
  • 至少n位的数字:“^\\d{n,}$”;
  • n-m位的数字:“^\\d{n}$”;
  • 0和非0的数字:“^(0|[1-9]\\d*)$”;

校验字符的正则表达式

  • 汉字:^[\\u4e00-\\u9fa5]{0,}$;
  • 英文和数字:[A-Za-z0-9]+^$;
  • 长度为3-20的所有字符:.{3,20}^$;
  • 由26个英文字母组成的字符串:^[A-Za-z]$;
  • 由数字、字母、下划线组成的字符串:^\\w+$;
  • 中文、英文、数字但不包含下划线等符号:^[\\u4e00-\\u9fa5A-Za-z0-9]$;
  • 可以输入含有 ^%&‘,;=?\ 等字符:^[^%&’,;=?\\\\]+$;
  • 禁止输入含有~的字符:^[^~]+$;

特殊需求的正则表达式

  • Emai1地址: \\w+([-+.]w+)*@\\w+([-.]\w+)*.\\w+([-.]\\w+)*$
  • 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
  • InternetURL:[a-zA-z]+:/[^\\s]*或^https:/([\\w-]+.)+[\\w-]+(/[\\w-./?%&=]*)?$
  • 手机号码:^(13[6-9]|14[5|7]115[9|1|2|3|516|78|9]|18[81|2|3|5|6|718|9])\\d{8}$
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

り澄忆秋、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值