Java 正则表达式

1. 正则表达式简介

正则表达式可以用字符串来描述规则,并用来匹配字符串

举个例子:要判断用户输入的年份是否是 20## 年。

规则:

2,0,0~9任意数字,0~9任意数字

正则表达式:

20\d\d

Java 字符串(Java 字符串用 \\ 表示 \):

20\\d\\d

代码:

public static boolean is20xx(String str) {
    return str.matches("20\\d\\d");
}

2. 正则表达式匹配规则

正则表达式的匹配规则是从左到右按规则匹配。

精确匹配

正则表达式1:

abc

它只能精确地匹配字符串 "abc"

正则表达式2:

a\&c

其中 \& 是用来匹配特殊字符 & 的,它只能精确匹配字符串 "a&c"

匹配任意字符

正则表达式:

a.c

其中 . 可以匹配一个任意字符,"abc""a&c""acc" 都可以匹配

匹配数字

正则表达式:

00\d

其中 \d 可以匹配 0~9 这样的数字,"007""008" 都可以匹配

匹配常用字符

正则表达式:

java\w

其中 \w 可以匹配一个字母、数字或下划线,"javac""java9""java_" 都可以匹配

匹配空格字符

正则表达式:

a\sc

其中 \s 可以匹配一个空格字符,注意空格字符不但包括空格,还包括 tab 字符

"a c""a\tc" 都可以匹配

匹配非数字

正则表达式:

00\D

其中 \D 可以匹配一个非数字,"00A""00#" 都可以匹配,但 "007" 不能匹配

类似的,\W 可以匹配 \w 不能匹配的字符,\S 可以匹配 \s 不能匹配的字符,这几个正好是反着来的

匹配任意个字符

正则表达式:

A\d*

其中 * 可以匹配任意个字符,"A""A0""A380" 都可以匹配

匹配至少一个字符

正则表达式:

A\d+

其中 + 可以匹配至少一个字符,"A0""A380" 都可以匹配,"A" 无法匹配,因为要求至少一个字符

匹配 0 个或一个字符

正则表达式:

A\d?

其中 ? 可以匹配 0 个或一个字符,"A""A0" 都可以匹配,"A380" 无法匹配,因为超过 1 个字符就不能匹配了。

精确指定 n 个字符

A\d{3}

其中 {3} 可以匹配 3 个字符,"A380" 都可以匹配

匹配 n~m 个字符

A\d{3,5}

其中 {3,5} 可以匹配 3-5 个字符,"A380""A3800""A38000" 都可以匹配

A\d{3,}

其中 {3,} 可以匹配至少 3 个字符

练习

请编写一个正则表达式匹配国内的电话号码规则:3~4 位区号加 7~8 位电话,中间用 - 连接,例如:010-12345678

public static boolean isTelphone(String str) {
    return str.matches("\\d{3,4}-\\d{7,8}");
}

3. 复杂匹配规则

匹配开头和结尾

用正则表达式进行多行匹配时,我们用 ^ 表示开头,$ 表示结尾。

正则表达式:

^A\d{3}$

"A001""A380" 都可以匹配

匹配指定范围

正则表达式:

[abcd]1

其中 [abcd] 可以匹配 a, b, c, d 任意一个字符,"a1""c1" 都可以匹配

上面的正则表达式等价于:

[a-d]1

如果要匹配多个范围可以这样写:

[a-dA-D]1

如果要匹配多个指定范围的字符,前面讲过的 {n} 仍然可以继续配合使用:

[a-dA-D]{6}

如果要匹配非指定范围的字符可以这样写:

[^a-dA-D]{6}

或规则匹配

正则表达式:

AB|CD

其中 | 连接的两个正则规则是或规则,ABCD 都可以匹配

使用括号

如果我们想要匹配 learn AB 或 learn CD,这时就需要使用括号了,目的是把 AB|CD 作为一个整体。

learn\s(AB|CD)

4. 分组匹配

实际上() 还有一个重要作用,就是分组匹配。

例如匹配国内的电话号码规则:3~4 位区号加 7~8 位电话。正则表达式如下:

\d{3,4}-\d{7,8}

但是往往匹配成功后,下一步是提取区号和电话号码,于是问题来了:如何提取匹配的子串?

正确的方法是用 () 先把要提取的规则分组,把上述正则表达式变为:

(\d{3,4})-(\d{7,8})

现在问题又来了:匹配后,如何按括号提取子串?

必须引入 java.util.regex 包,用 Pattern 对象匹配,匹配后获得一个 Matcher 对象,如果匹配成功,就可以直接从 Matcher.group(index) 返回子串:

public class test1 {
	public static void main(String[] args) {
		Pattern p = Pattern.compile("(\\d{3,4})-(\\d{7,8})");
		Matcher m = p.matcher("010-12345678");
		if (m.matches()) {
			String str1 = m.group(1);
			String str2 = m.group(2);
			System.out.println(str1);
			System.out.println(str2);
		} else {
			System.out.println("匹配失败");
		}
	}
}

运行结果:

010
12345678

5. 非贪婪匹配

在介绍非贪婪匹配前,我们先看一个简单的问题:

给定一个字符串表示的数字,判断该数字末尾 0 的个数。例如:

  • "123000":3 个0
  • "10100":2 个0
  • "1001":0 个0

可以很容易地写出该正则表达式:(\d+)(0*),Java 代码如下:

public class test1 {
	public static void main(String[] args) {
		Pattern pattern = Pattern.compile("(\\d+)(0*)");
        Matcher matcher = pattern.matcher("1230000");
        if (matcher.matches()) {
            System.out.println("group1=" + matcher.group(1)); 
            System.out.println("group2=" + matcher.group(2)); 
        }
	}
}

运行结果:

group1=1230000
group2=

然而打印的第二个子串是空字符串 “”。

这是因为正则表达式默认使用贪婪匹配:任何一个规则,它总是尽可能多地向后匹配,因此,\d+ 总是会把后面的 0 包含进来。

要让 \d+ 尽量少匹配,让 0* 尽量多匹配,我们就必须让 \d+ 使用非贪婪匹配。在规则 \d+ 后面加个 ? 即可表示非贪婪匹配。

我们改写正则表达式如下:

public class test1 {
	public static void main(String[] args) {
		Pattern pattern = Pattern.compile("(\\d+?)(0*)");
        Matcher matcher = pattern.matcher("1230000");
        if (matcher.matches()) {
            System.out.println("group1=" + matcher.group(1)); 
            System.out.println("group2=" + matcher.group(2)); 
        }
	}
}

运行结果:

group1=123
group2=0000

6. 搜索和替换

分割字符串

使用正则表达式分割字符串可以实现更加灵活的功能。String.split() 方法传入的正是正则表达式。

"a b c".split("\\s"); // { "a", "b", "c" }
"a b  c".split("\\s"); // { "a", "b", "", "c" }
"a b  c".split("\\s+"); // { "a", "b", "c" }
"a, b ;; c".split("[\\,\\;\\s]+"); // { "a", "b", "c" }

搜索字符串

我们获取到 Matcher 对象后,反复调用 find() 方法,在整个串中搜索能匹配上正则表达式的子串,并打印出来。

public class test1 {
	public static void main(String[] args) {
		String s = "The quick brown fox jumps over the lazy dog.";
		// 查找 the,不区分大小写
        Pattern p1 = Pattern.compile("the", Pattern.CASE_INSENSITIVE);
        // 查找每一个单词
        Pattern p2 = Pattern.compile("\\w+");
		// 查找单词中包含 o 的单词
		Pattern p3 = Pattern.compile("\\w*o\\w*");
        Matcher m = p1.matcher(s);
        while (m.find()) {
            String sub = s.substring(m.start(), m.end());
            System.out.println(sub + " start=" + m.start() + " end=" + m.end());
        }
	}
}

p1 正则表达式运行结果:

The start=0 end=3
the start=31 end=34

p2 正则表达式运行结果:

The start=0 end=3
quick start=4 end=9
brown start=10 end=15
fox start=16 end=19
jumps start=20 end=25
over start=26 end=30
the start=31 end=34
lazy start=35 end=39
dog start=40 end=43

p3 正则表达式运行结果:

brown start=10 end=15
fox start=16 end=19
over start=26 end=30
dog start=40 end=43

替换字符串

使用正则表达式替换字符串可以直接调用 String.replaceAll(),它的第一个参数是正则表达式,第二个参数是待替换的字符串。

public class test1 {
	public static void main(String[] args) {
		// 把多余的空格变为一个空格
        String s = "The     quick\t\t brown   fox  jumps   over the  lazy dog.";
        String r = s.replaceAll("\\s+", " ");
        System.out.println(r); 
	}
}

运行结果:

The quick brown fox jumps over the lazy dog.
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

bm1998

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

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

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

打赏作者

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

抵扣说明:

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

余额充值