一、正则表达式引入
1、概述
-
正则表达式(regular expression,简称 RegExp)是处理文本的利器,是对字符串执行模式匹配的技术
-
例如,使用传统方式提取内容中的所有英文单词就要使用遍历,代码量大,且效率不高,但是正则表达式就可以简化这些操作
2、初体验
- 提取内容中所有的英文单词
java">String content = "由于在开发Oak语言时,尚且不存在运行字节码的硬件平台,所以为了在开发时可以对这种语言进行实验研究," +"他们就在已有的硬件和软件平台基础上,按照自己所指定的规范,用软件建设了一个运行平台,整个系统除了比C++更加简单之外," +"没有什么大的区别。1992年的夏天,当Oak语言开发成功后,研究者们向硬件生产商进行演示了Green操作系统、Oak的程序设计语言、" +"类库和其硬件,以说服他们使用Oak语言生产硬件芯片,但是,硬件生产商并未对此产生极大的热情。因为他们认为,在所有人对Oak语言" +"还一无所知的情况下,就生产硬件产品的风险实在太大了,所以Oak语言也就因为缺乏硬件的支持而无法进入市场,从而被搁置了下来。";// 1、创建一个 Pattern 对象(模式对象,可以理解成一个正则表达式对象)
Pattern pattern = Pattern.compile("[a-zA-Z]+");// 2、创建一个匹配器对象
// 理解:matcher 按照 pattern 到 content 中去匹配
// 找到就返回 true,未找到就返回 false
Matcher matcher = pattern.matcher(content);// 3、开始循环匹配
while (matcher.find()) {// 匹配到的内容放到 atcher.group(0) 中System.out.println(matcher.group(0));
}
- 输出结果
Oak
C
Oak
Green
Oak
Oak
Oak
Oak
3、更多演示
- 提取内容中所有的数字
java">String content = "由于在开发Oak语言时,尚且不存在运行字节码的硬件平台,所以为了在开发时可以对这种语言进行实验研究," +"他们就在已有的硬件和软件平台基础上,按照自己所指定的规范,用软件建设了一个运行平台,整个系统除了比C++更加简单之外," +"没有什么大的区别。1992年的夏天,当Oak语言开发成功后,研究者们向硬件生产商进行演示了Green操作系统、Oak的程序设计语言、" +"类库和其硬件,以说服他们使用Oak语言生产硬件芯片,但是,硬件生产商并未对此产生极大的热情。因为他们认为,在所有人对Oak语言" +"还一无所知的情况下,就生产硬件产品的风险实在太大了,所以Oak语言也就因为缺乏硬件的支持而无法进入市场,从而被搁置了下来。";Pattern pattern = Pattern.compile("[0-9]+");
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
1992
- 提取内容中所有的英文单词和数字
java">String content = "由于在开发Oak语言时,尚且不存在运行字节码的硬件平台,所以为了在开发时可以对这种语言进行实验研究," +"他们就在已有的硬件和软件平台基础上,按照自己所指定的规范,用软件建设了一个运行平台,整个系统除了比C++更加简单之外," +"没有什么大的区别。1992年的夏天,当Oak语言开发成功后,研究者们向硬件生产商进行演示了Green操作系统、Oak的程序设计语言、" +"类库和其硬件,以说服他们使用Oak语言生产硬件芯片,但是,硬件生产商并未对此产生极大的热情。因为他们认为,在所有人对Oak语言" +"还一无所知的情况下,就生产硬件产品的风险实在太大了,所以Oak语言也就因为缺乏硬件的支持而无法进入市场,从而被搁置了下来。";Pattern pattern = Pattern.compile("([a-zA-Z]+)|([0-9]+)");
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
Oak
C
1992
Oak
Green
Oak
Oak
Oak
Oak
- 提取内容中的 IP 地址
java">String content = "10.1.1.1\n" +"\n" +"255.255.0.0\n" +"\n" +"10.1.1.1属于哪个网段?所在网段有多少个IP地址?该网段的广播地址是什么?\n" +"\n" +"答:\n" +"\n" +"10.1.1.1属于10.1.0.0网段。\n" +"\n" +"10.1.0.0网段可用的IP地址范围:10.1.0.1-10.1.255.254(65534)\n" +"\n" +"10.1.1.0网段的广播地址:10.1.255.255";Pattern pattern = Pattern.compile("\\d+\\.\\d+\\.\\d+\\.\\d+");
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
10.1.1.1
255.255.0.0
10.1.1.1
10.1.1.1
10.1.0.0
10.1.0.0
10.1.0.1
10.1.255.254
10.1.1.0
10.1.255.255
二、正则表达式底层实现
1、基本介绍
2、案例分析
(0)案例代码
- 匹配内容中的连续的四个数字
java">String content = "1998年12月8日,第二代Java平台的企业版J2EE发布。1999年6月,Sun公司发布了第二代Java平台(简称为Java2" +")的3个版本:J2ME(Java2 Micro Edition,Java2平台的微型版),应用于移动、无线及有限资源的环境;J2SE" +"(Java 2 Standard Edition,Java 2平台的标准版),3443应用于桌面环境;J2EE(Java 2Enterprise Edition," +"Java 2平台的企业版),应用于基于Java的应用服务器。Java 2平台的发布," +"是Java发展过程中最重要的一个里程碑,9889标志着Java的应用开始普及。";// \\d 表示一个任意数字(0 ~ 9)
String regStr = "\\d\\d\\d\\d";Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
1998
1999
3443
9889
(1)matcher.find()
-
根据指定的规则,定位满足规则的字符串
-
定位到后,将子字待串的索引记录到 matcher 的属性
int[] groups;
中,例如,1998...
,会将子字符串开始的索引记录groups[0] = 0;
,会将子字符串结束的索引 + 1 记录groups[1] = 4;
-
同时记录 oldlast,即子字符串结束的索引 + 1,例如,这里就是 4,记录的作用是下次从这里开始匹配
(2)matcher.group(0)
public String group(int group) {if (first < 0)throw new IllegalStateException("No match found");if (group < 0 || group > groupCount())throw new IndexOutOfBoundsException("No group " + group);if ((groups[group*2] == -1) || (groups[group*2+1] == -1))return null;return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
}
- 根据 groups[0] 和 groups[1] 的记录,从原字符串开始截取子字符串,左闭右开,这里就是 [0, 4)
3、分组分析
(0)案例代码
java">...String regStr = "(\\d\\d)(\\d\\d)";...while (matcher.find()) {System.out.println(matcher.group(0));System.out.println("第一个分组:" + matcher.group(1));System.out.println("第二个分组:" + matcher.group(2));
}
- 输出结果
1998
第一个分组:19
第二个分组:98
1999
第一个分组:19
第二个分组:99
3443
第一个分组:34
第二个分组:43
9889
第一个分组:98
第二个分组:89
(1)分组概述
- 正则表达式里有小括号(())表示分组,第一个小括号表示第一组,第二个小括号表示第二组
(2)matcher.find()
-
根据指定的规则,定位满足规则的字符串
-
定位到后,将子字待串的索引记录到 matcher 的属性
int[] groups;
中,例如,1998...
,会将子字符串开始的索引记录groups[0] = 0;
,会将子字符串结束的索引 + 1 记录groups[1] = 4;
,对第一个分组进行索引记录groups[2] = 0;
groups[3] = 2;
,对第二个分组进行索引记录groups[4] = 2;
groups[5] = 4;
-
同时记录 oldlast,即子字符串结束的索引 + 1,例如,这里就是 4,记录的作用是下次从这里开始匹配
(3)matcher.group()
-
matcher.group(0) 表示匹配到的子字符串
-
matcher.group(1) 表示匹配到的子字符串的第一个分组
-
matcher.group(2) 表示匹配到的子字符串的第二个分组
- 注:分组数量不能越界,否则报错
三、元字符
0、转义符
(1)基本介绍
java">*
+
()
[]
{}
$
/\
?
^
(2)演示
- 错误演示
String content = "123(456(";String regStr = "(";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
Exception in thread "main" java.util.regex.PatternSyntaxException: Unclosed group near index 1
(
- 使用转义符正确匹配
java">String content = "123(456(";String regStr = "\\(";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
(
(
1、字符匹配符
(1)基本介绍
符号 | 说明 | 示例 |
---|---|---|
[] | 可接收的字符序列 | [abcd] :a、b、c、d 中的任意一个字符 |
[^] | 可接收的字符序列 | [^bc] :除 a、b、c 的任意一个字符,包括数字和特殊符号 |
- | 连字符 | A-Z :任意单个大写字面 |
. | 匹配除 \n 以外任意字符 | a..b :以 a 开头,b 结尾,中间包括 2 个任意字符的长度为 4 的字符串 |
\\d | 匹配单个数字字符 相当于 [0-9] | \\d{3}(\\d)? :匹配 3 个或 4 个数字的字符串 |
\\D | 匹配单个非数字字符 | \\D(\\d)* :以单个非数字字符开头,后接任意个数字字符串 |
\\w | 匹配单个数字和大小写字母字符 相当于 [0-9a-zA-Z] | \\d{3}\\w{4} :以 3 个数字字符开头的长度为 7 的数字字母字符串 |
\\W | 匹配单个非数字和大小写字母字符 相当于 [^0-9a-zA-Z] | \\W+\\d{2} :以至少 1 个非数字字母字符开头,2 个数字字符结尾的字符串 |
(2)演示
- 匹配 a - z 之间的任意一个字符(
[0-9]
、[A-Z]
同理)
java">String content = "a11c8";String regStr = "[a-z]";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
a
c
- 不区分大小写匹配
java">String content = "a11c8ABC123abc456Abc";String regStr = "(?i)abc";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
java">// 等同于
String content = "a11c8ABC123abc456Abc";String regStr = "abc";
Pattern pattern = Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
示例 | 说明 |
---|---|
(?i)abc | a、b、c 都不区分大小写 |
a(?i)bc | b、c 不区分大小写 |
a((?i)b)c | 只有 b 不区分大小写 |
- 输出结果
ABC
abc
Abc
- 匹配不是 a - z 之间的任意一个字符(
[0-9]
、[A-Z]
同理)
java">String content = "a11c8";String regStr = "[^a-z]";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
1
1
8
- 匹配 a、b、c、d 中的任意一个字符(
[^abcd]
则是匹配不是 a、b、c、d 中的任意一个字符)
java">String content = "a11c8zyx";String regStr = "[abcd]";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
a
c
- 匹配字母、数字、下划线
java">String content = "a11c8zyx&*#@_";String regStr = "\\w";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
a
1
1
c
8
z
y
x
_
- 匹配非字母、数字、下划线
java">String content = "a11c8zyx&*#@_";String regStr = "\\W";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
&
*
#
@
- 匹配任何空白字符(空格、制表符等)
java">String content = "a1 1c8zy x&*#@_";String regStr = "\\s";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println("-" + matcher.group(0) + "-");
}
- 输出结果
- -
- -
- -
- 匹配任何非空白字符
java">String content = "a1 1c8zy x&*#@_";String regStr = "\\S";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
a
1
1
c
8
z
y
x
&
*
#
@
_
- 匹配除
\n
之外的所有字符
java">String content = "a1 1cy\n#@_";String regStr = ".";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
a
11
c
y
#
@
_
- 匹配
.
自身
java">String content = "a.1 1c.y\n#@_";String regStr = "\\.";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
.
.
2、选择匹配符
(1)基本介绍
符号 | 说明 | 示例 |
---|---|---|
` | ` | 匹配 ` |
(2)演示
java">String content = "sunke 孙 helloworld";String regStr = "sunke|孙|hello";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
sunke
孙
hello
3、限定符
(1)基本介绍
- 限定符用于指定其前面的字符和组合项连续出现多少次
符号 | 说明 | 示例 |
---|---|---|
* | 指定字符重复 0 次或 n 次 | (abc)* :包含任意个 abc 的字符串,等效于 \w* |
+ | 指定字符重复 1 次或 n 次 | m+(abc)* :以至少 1 个 m 开头,后接任意个 abc 的字符串 |
? | 指定字符重复 0 次或 1 次 | m+abc? :以至少 1 个 m 开头,后接 ab 或 abc 的字符串 |
{n} | 只能输入 n 个字符 | [abcd]{3} :由 a、b、c、d 组成的任意长度为 3 的字符串 |
{n,} | 指定至少 n 个匹配 | [abcd]{3,} :由 a、b、c、d 组成的任意长度不小于 3 的字符串 |
{n,m} | 指定至少 n 个但不多于 m 个匹配 | [abcd]{3,5} :由 a、b、c、d 组成的任意长度不小于 3 且不大于 5 的字符串 |
(2)演示
- 匹配 1111
java">String content = "11123111123456123";String regStr = "1{4}";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
1111
- 匹配两位数字
java">String content = "123abc4567";String regStr = "\\d{2}";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
12
45
67
- 匹配 aaa 或 aaaa
- 注:Java 中的正则匹配默认是贪婪匹配,即尽可能多的匹配
java">String content = "aaaa123123aaa";String regStr = "a{3,4}";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
aaaa
aaa
- 匹配一个 1 或多个 1
java">String content = "aaaa123121232341211113aaa";String regStr = "1+";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
1
1
1
1
1111
- 匹配 a 后接任意个 1
java">String content = "aaaa123121232341211113aaa";String regStr = "a1*";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
a
a
a
a1
a
a
a
- 匹配 a 后接 0 个或 1 个 1
- 注:遵循贪婪匹配
java">String content = "a1111123121232341211113aaa";String regStr = "a1?";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
a1
a
a
a
4、定位符
(1)基本介绍
- 定位符规定要匹配的字符串出现的位置,例如,在字符串的开始还是在结束的位置
符号 | 说明 | 示例 |
---|---|---|
^ | 指定起始字符 | ^[0-9]+[a-z]* :以至少 1 个数字开头,后接任意个小写字母的字符串 |
$ | 指定结束字符 | ^[0-9]\\-[a-z]+$ :以 1 个数字开头,后接 -,以至少 1 个小写字母结尾的字符串 |
\\b | 匹配原字符串的边界 | han\\b :这里的边界指的是子串间有空格,或者是原字符串的结束位置 |
\\B | 匹配原字符串的非边界 | - |
(2)演示
- 以至少 1 个数字开头,后接任意个小写字面
java">String content = "111abc#1ac";String regStr = "^[0-9]+[a-z]*";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
111abc
- 以至少 1 个数字开头,以至少 1 个小写字面结尾
java">String content = "111a";String regStr = "^[0-9]+[a-z]+$";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
111a
- 匹配边界的 sun
java">String content = "sunke hellosun worldsun";String regStr = "sun\\b";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
sun
sun
- 匹配非边界的 sun
java">String content = "sunke hellosun worldsun";String regStr = "sun\\B";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
sun
四、正则表达式其他语法
1、捕获分组
(1)基本介绍
分组形式 | 说明 |
---|---|
(【pattern】) | 非命名捕获,捕获匹配的子字符串 1、编号为 0 的第一个捕获是由整个正则表达式模式匹配的文本 2、其它捕获结果则根据括号的顺序从 1 开始自动编号 |
(?<【name】>【pattern】) | 命名捕获,将匹配的子字符串捕获到一个组名称或编号名称中 用于 name 的字符串不能包含任何标点符号,并且不能以数字开头 可以使用单引号替代尖括号,例如, (?'【name】') |
(2)演示
- 使用非命名捕获,匹配 4 个数字
java">String content = "1231hjkasd879090ad";String regStr = "(\\d\\d)(\\d\\d)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));System.out.println("第一个分组:" + matcher.group(1));System.out.println("第二个分组:" + matcher.group(2));
}
- 输出结果
1231
第一个分组:12
第二个分组:31
8790
第一个分组:87
第二个分组:90
- 使用命名捕获,匹配 4 个数字
java">String content = "1231hjkasd879090ad";String regStr = "(?<g1>\\d\\d)(?<g2>\\d\\d)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));System.out.println("第一个分组:" + matcher.group(1));System.out.println("第一个分组:" + matcher.group("g1"));System.out.println("第二个分组:" + matcher.group(2));System.out.println("第二个分组:" + matcher.group("g2"));
}
- 输出结果
1231
第一个分组:12
第一个分组:12
第二个分组:31
第二个分组:31
8790
第一个分组:87
第一个分组:87
第二个分组:90
第二个分组:90
2、特别分组
(1)基本介绍
分组形式 | 说明 |
---|---|
(?:【pattern】) | 匹配 pattern 但不捕获该匹配的子表达式 它是一个非捕获匹配,不存储供以后使用的匹配 这对于使用 ` |
(?=【pattern】) | 它是一个非捕获匹配 例如,`Windows (?=95 |
(?!【pattern】) | 它是一个非捕获匹配 该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串 例如,`Windows (?!95 |
(2)演示
- 匹配 “韩顺平教育”、“韩顺平老师”、“韩顺平同学”
java">String content = "hello韩顺平教育 jack韩顺平老师 韩顺平同学hello";// String regStr = "韩顺平教育|韩顺平老师|韩顺平同学";
String regStr = "韩顺平(?:教育|老师|同学)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));// 不能这么做// System.out.println(matcher.group(1));
}
- 输出结果
韩顺平教育
韩顺平老师
韩顺平同学
- 匹配 “韩顺平教育”、“韩顺平老师” 中的 “韩顺平”
java">String content = "hello韩顺平教育 jack韩顺平老师 韩顺平同学hello";String regStr = "韩顺平(?=教育|老师)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
韩顺平
韩顺平
- 匹配不是 “韩顺平教育”、“韩顺平老师” 中的 “韩顺平”
java">String content = "hello韩顺平教育 jack韩顺平老师 韩顺平同学hello";String regStr = "韩顺平(?!教育|老师)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
韩顺平
3、非贪婪匹配
(1)基本介绍
- 当
?
字符紧随任何其他限定符之后时(*、+、?、{n}、{n,}、{n,m}
),匹配模式是非贪婪匹配,非贪婪匹配是匹配搜索到的尽可能短的字符串
(2)演示
java">String content = "sunke123123 hellosun123123 worldsun";String regStr = "\\d+?";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
1
2
3
1
2
3
1
2
3
1
2
3
五、应用实例
1、匹配汉字
java">String content = "你好啊";String regStr = "^[\u0391-\uffe5]+$";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
System.out.println(matcher.find());
2、匹配邮政编码
- 邮政编码是以 1 ~ 9 开头的 6 位数字
java">String content = "123890";String regStr = "^[1-9]\\d{5}";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
System.out.println(matcher.find());
3、匹配 QQ 号
- QQ 号是以 1 ~ 9 开头的 5 ~ 10 位数字
java">String content = "2172302933";String regStr = "^[1-9]\\d{4,9}";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
System.out.println(matcher.find());
4、匹配手机号码
- 手机号码是以 13、14、15、18 开头的 11 位数字
java">String content = "13768528292";String regStr = "^[13|14|15|18]\\d{9}";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
System.out.println(matcher.find());
5、匹配 URL
java">String content = "https://www.bilibili.com/video/BV1Eq4y1E79W?p=17&vd_source=d0beb2b36d04c38a32ed203125b4cbcd";String regStr = "^((http|https)://)([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%#.]*)*$";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
System.out.println(matcher.find());
六、正则表达式常用类
1、基本介绍
- java.util.regex 包主要包括三个类:Matcher、Pattern、PatternSyntaxException
-
Pattern:Pattern 对象是一个正则表达式对象,Pattern 类没有公共构造方法,要创建一个 Pattern 对象,需要调用其公共静态方法,该方法接受一个正则表达式作为它的第一个参数
-
Matcher 类:Matcher 对象是对输入字符串进行解释和匹配的引擎,与Pattern 类一样,Matcher 类也没有公共构造方法,需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象
-
PatternSyntaxException 类:它是一个非强制异常类,表示一个正则表达式模式中的语法错误
2、Pattern 类常用方法
(1)基本介绍
- Pattern 类的常用方法是 matches,原码如下,本质还是创建并使用了了 Pattern 对象和 Matcher 对象
java">public static boolean matches(String regex, CharSequence input) {Pattern p = Pattern.compile(regex);Matcher m = p.matcher(input);return m.matches();
}
(2)演示
java">String content = "你好啊";String regStr = "^[\u0391-\uffe5]+$";
boolean res = Pattern.matches(regStr, content);
System.out.println("整体匹配结果:" + res);
3、Matcher 类常用方法
(1)基本介绍
- 常用方法
方法 | 说明 |
---|---|
int start() | 返回以前匹配的初始索引 |
int end() | 返回最后匹配之后的偏移量 |
boolean find() | 尝试查找与该模式匹配的输入序列的下一个子序列 |
boolean matches() | 尝试将整个区域与模式匹配 |
public String replaceAll(String replacement) | 替换模式与给定替换字符串相匹配的输入序列的每个子序列 它不会改变原字符串,会返回新的字符串 |
(2)演示
- start 方法与 end 方法
java">String content = "hello edu jack tom hello smith hello";String regStr = "hello";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println("====================");System.out.println(matcher.start());System.out.println(matcher.end());System.out.println("找到:" + content.substring(matcher.start(), matcher.end()));
}
- 输出结果
====================
0
5
找到:hello
====================
19
24
找到:hello
====================
31
36
找到:hello
- matches 方法
java">String content = "hello edu jack tom hello smith hello";String regStr = "hello.*";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
System.out.println("整体匹配结果:" + matcher.matches());
- 输出结果
整体匹配结果:true
- replaceAll 方法:将”hello”替换成”你好啊“
java">String content = "hello edu jack tom hello smith hello";String regStr = "hello";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
String newContent = matcher.replaceAll("你好啊");
System.out.println(newContent);
- 输出结果
你好啊 edu jack tom 你好啊 smith 你好啊
七、反向引用
1、基本使用
-
给你一段文本,请你找出所有四个数字连在一起的子串,并且这四个数字要满足第 1 位与第 4 位相同,第 2 位与第 3 位相同
-
要解决该问题,需要了解正则表达式的几个概念
-
分组:用圆括号(())组成一个比较复杂的匹配模式,一个圆括号的部分可以看作是一个子表达式(一个分组)
-
捕获:把正则表达式中子表达式(分组)匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右,以分组的左括号为标志,第一个出现的分组的组号为 1,第二个为 2,以此类推,组 0 代表的是整个正则式
-
反向引用:圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,这样的方式被称为反向引用,这种引用既可以是在正则表达式内部,也可以是在正则表达式外部,内部反向引用为
\\【分组号】
,外部反向引用为$【分组号】
2、演示
- 匹配两个连续的相同数字
java">String content = "hello 11 edu 22 jack 34 tom 1234 hello 55 smith 666 hello";String regStr = "(\\d)\\1";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
11
22
55
66
- 匹配五个连续的相同数字
java">String content = "hello 11111 edu 22222 jack 34 tom 1234 hello 55 smith 666 hello";// String regStr = "(\\d)\\1\\1\\1\\1";
String regStr = "(\\d)\\1{4}";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
11111
22222
- 匹配第 1 位与第 4 位相同,第 2 位与第 3 位相同的数字
java">String content = "hello 21121 edu 22222 jack 34 tom 1221 hello 55 smith 666 hello";String regStr = "(\\d)(\\d)\\2\\1";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {System.out.println(matcher.group(0));
}
- 输出结果
2112
2222
1221
- 结巴去重问题
java">String content = "我...要要...学学 Java";// 1、去掉所有的点
Pattern pattern = Pattern.compile("\\.");
Matcher matcher = pattern.matcher(content);
content = matcher.replaceAll("");// 2、去重,将重复 N 次的字替换成 1 个字
// 因为正则表达式的变化,所以需要重置 matcher
pattern = Pattern.compile("(.)\\1+");
matcher = pattern.matcher(content);
content = matcher.replaceAll("$1");System.out.println(content);
- 输出结果
我要学 Java
八、String 类的正则支持
1、基本介绍
-
String 类的
public String replaceAll(String regex, String replacement)
,支持正则替换,它不会改变原字符串,会返回新的字符串 -
public boolean matches(String regex)
支持正则匹配 -
public String[] split(String regex)
支持正则分割
2、演示
- 替换 JDK1.3 和 JDK1.4 为 JDK
java">String content = "2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。";content = content.replaceAll("JDK\\d.\\d", "JDK");System.out.println(content);
- 输出结果
2000年5月,JDK、JDK和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。
- 验证一个手机号,必须以 138 或 139 开头
java">String content = "13877791234";System.out.println(content.matches("^13(?:8|9)\\d{8}"));
- 输出结果
true
- 按”=“、”&“、”#“、”$“分割
java">String content = "sunke=123123&hello#sun&123$123";String[] resArr = content.split("=|#|\\$|&");
for (String s : resArr) {System.out.println(s);
}
- 输出结果
sunke
123123
hello
sun
123
123