https://blog.csdn.net/m0_62618110/article/details/123704869

Java 正则表达式

0 概述

简介

正则表达式(regex)是一个字符串,由字面值字符和特殊符号组成,是用来描述匹配一个字符串集合的模式,可以用来匹配、查找字符串。

正则表达式的两个主要作用:

  • 查找:在字符串中查找符合固定模式的子串
  • 匹配:整个字符串是否符合某个格式

在匹配和查找的基础上,实现替换、分割等操作。

基本实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches
{
public static void main( String[] args ){

// 按指定模式在字符串查找
String line = "This order was placed for QT3000! OK?";
String pattern = "(\\D*)(\\d+)(.*)";

// 创建 Pattern 对象
Pattern r = Pattern.compile(pattern);

// 现在创建 matcher 对象
Matcher m = r.matcher(line);
if (m.find( )) {
System.out.println("Found value: " + m.group(0) );
System.out.println("Found value: " + m.group(1) );
System.out.println("Found value: " + m.group(2) );
System.out.println("Found value: " + m.group(3) );
} else {
System.out.println("NO MATCH");
}
}
}

1 正则表达式语法

  • 在其他语言中,\\表示:我想要在正则表达式中插入一个普通的(字面上的)反斜杠,请不要给它任何特殊的意义。
  • 在 Java 中,\\ 表示:我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。
  • 不要在重复词符中使用空白。如B{3,6} ,不能写成 B{3, 6}。空格也是有含义的。
  • 可以使用括号来将模式分组。(ab){3}匹配ababab , 而ab{3} 匹配 abbb。
字符 匹配 示例
. 任意单个字符,除换行符外 jav.匹配java
[ ] [ ] 中的任意一个字符 java匹配j[abc]va
- [ ] 内表示字符范围 java匹配[a-z]av[a-g]
^ 在[ ]内的开头,匹配除[ ]内的字符之外的任意一个字符 java匹配j[^b-f]va
\ 将下一字符标记为特殊字符、文本、反向引用或八进制转义符 (匹配(
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与”\n”或”\r”之前的位置匹配。 ;$匹配位于一行及外围的;号
* 零次或多次匹配前面的字符 zo*匹配zoo或z
+ 一次或多次匹配前面的字符 zo+匹配zo或zoo
? 零次或一次匹配前面的字符 zo?匹配z或zo
p{n} n 是非负整数。正好匹配 n 次 o{2}匹配food中的两个o
p{n,} n 是非负整数。至少匹配 n 次 o{2}匹配foood中的所有o
p{n,m} M 和 n 是非负整数,其中 n<= m。匹配至少 n 次,至多 m 次 o{1,3}匹配fooood中的三个o
\p{P} 一个标点字符 !”#$%&’()*+,-./:;<=>?@[]^_’{ }~
\b 匹配一个字边界 va\b匹配java中的va,但不匹配javar中的va
\B 非字边界匹配 va\B匹配javar中的va,但不匹配java中的va
\d 数字字符匹配 1[\d]匹配13
\D 非数字字符匹配 [\D]java匹配Jjava
\w 单词字符 java匹配[\w]ava
\W 非单词字符 $java匹配[\W]java
\s 空白字符 Java 2匹配Java\s2
\S 非空白字符 java匹配 j[\S]va
\f 匹配换页符 等效于\x0c和\cL
\n 匹配换行符 等效于\x0a和\cJ

分组说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
正则表达式-字符类

- 语法示例:

1. \[abc\]:代表a或者b,或者c字符中的一个。
2. \[^abc\]:代表除a,b,c以外的任何字符。
3. [a-z]:代表a-z的所有小写字符中的一个。
4. [A-Z]:代表A-Z的所有大写字符中的一个。
5. [0-9]:代表0-9之间的某一个数字字符。
6. [a-zA-Z0-9]:代表a-z或者A-Z或者0-9之间的任意一个字符。
7. [a-dm-p]:a 到 d 或 m 到 p之间的任意一个字符。

正则表达式-逻辑运算符

- 语法示例:
1. &&:并且
2. | :或者

正则表达式-预定义字符

- 语法示例:
1. "." : 匹配任何字符。
2. "\d":任何数字[0-9]的简写;
3. "\D":任何非数字\[^0-9\]的简写;
4. "\s": 空白字符:[ \t\n\x0B\f\r] 的简写
5. "\S": 非空白字符:\[^\s\] 的简写
6. "\w":单词字符:[a-zA-Z_0-9]的简写
7. "\W":非单词字符:\[^\w\]

正则表达式-数量词

- 语法示例:
1. X? : 0次或1次
2. X* : 0次到多次
3. X+ : 1次或多次
4. X{n} : 恰好n次
5. X{n,} : 至少n次
6. X{n,m}: n到m次(n和m都是包含的)


正则表达式-分组括号()

2 基本概念

Patter类和Matcher类

Pattern 类:
pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。

Matcher 类:
Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。

匹配模式

1、Pattern.MULTILINE模式的用法

正则表达式中出现了^或者$, 默认只会匹配第一行. 设置了Pattern.MULTILINE模式,会匹配所有行。例如,

1
2
3
4
5
6
Pattern p1 = Pattern.compile("^.*b.*$");
//输出false,因为正则表达式中出现了^或$,默认只会匹配第一行,第二行的b匹配不到。
System.out.println(p1.matcher("a\nb").find());
Pattern p2 = Pattern.compile("^.*b.*$",Pattern.MULTILINE);
//输出true,指定了Pattern.MULTILINE模式,就可以匹配多行了。
System.out.println(p2.matcher("a\nb").find());

2、Pattern.DOTALL模式的用法

默认情况下, 正则表达式中点(.)不会匹配换行符, 设置了Pattern.DOTALL模式, 才会匹配所有字符包括换行符。例如,

1
2
3
4
5
6
Pattern p1 = Pattern.compile("a.*b");
//输出false,默认点(.)没有匹配换行符
System.out.println(p1.matcher("a\nb").find());
Pattern p2 = Pattern.compile("a.*b", Pattern.DOTALL);
//输出true,指定Pattern.DOTALL模式,可以匹配换行符。
System.out.println(p2.matcher("a\nb").find());

3、同时指定Pattern.MULTILINE和Pattern.DOTALL模式

实际情况中要是比较复杂的情况,可能Pattern.MULTILINE模式和Pattern.DOTAL模式需要同时指定来匹配多行,下面看一下,

1
2
3
4
5
6
7
8
9
10
11
12
13
Pattern p1 = Pattern.compile("^a.*b$");
//输出false
System.out.println(p1.matcher("cc\na\nb").find());
Pattern p2 = Pattern.compile("^a.*b$", Pattern.DOTALL);
//输出false,因为有^或&没有匹配到下一行
System.out.println(p2.matcher("cc\na\nb").find());
Pattern p3 = Pattern.compile("^a.*b$", Pattern.MULTILINE);
//输出false,匹配到下一行,但.没有匹配换行符
System.out.println(p3.matcher("cc\na\nb").find());
//指定多个模式,中间用|隔开
Pattern p4 = Pattern.compile("^a.*b$", Pattern.DOTALL|Pattern.MULTILINE);
//输出true
System.out.println(p4.matcher("cc\na\nb").find());

捕获组

  1. 捕获组是把多个字符当成一个单独单元进行处理的方法,它通过对括号内的字符分组来创建。
1
2
3
4
5
6
7
8
捕获组通过从左到右计算其括号来编号。

例如:在表达式((A)(B(C))) 中,存在四个这样的组:

((A)(B(C)))
(A)
(B(C))
(C)
  1. 捕获组可以通过调用matcher对象的groupCount方法来查看表达式有多少个分组。(groupCount方法返回一个int值,来表示matcher对象当前有多少个捕获组)
  2. 还有一个特殊的组零(group(0)),它代表整个表达式。(该组不包括在groupCount的返回值中)
  3. 以 (?) 开头的组是纯的非捕获 组,它不捕获文本,也不针对组合计进行计数。

3 Matcher用法

索引方法

  1. public int start()
    返回以前匹配的初始索引。
  2. public int start(int group)
    返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引
  3. public int end()
    返回最后匹配字符之后的偏移量。
  4. public int end(int group)
    返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches
{
private static final String REGEX = "\\bcat\\b";
private static final String INPUT =
"cat cat cat cattie cat";

public static void main( String[] args ){
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT); // 获取 matcher 对象
int count = 0;

while(m.find()) {
count++;
System.out.println("Match number "+count);
System.out.println("start(): "+m.start());
System.out.println("end(): "+m.end());
}
}
}

匹配和查找方法

  1. public boolean lookingAt()
    尝试将从区域开头开始的输入序列与该模式匹配。开头匹配。
  2. public boolean find()
    尝试查找与该模式匹配的输入序列的下一个子序列。
  3. public boolean find(int start)
    重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。
  4. public boolean matches()
    尝试将整个区域与模式匹配。全局匹配。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches
{
private static final String REGEX = "foo";
private static final String INPUT = "fooooooooooooooooo";
private static final String INPUT2 = "ooooofoooooooooooo";
private static Pattern pattern;
private static Matcher matcher;
private static Matcher matcher2;

public static void main( String[] args ){
pattern = Pattern.compile(REGEX);
matcher = pattern.matcher(INPUT);
matcher2 = pattern.matcher(INPUT2);

System.out.println("Current REGEX is: "+REGEX);
System.out.println("Current INPUT is: "+INPUT);
System.out.println("Current INPUT2 is: "+INPUT2);


System.out.println("lookingAt(): "+matcher.lookingAt());
System.out.println("matches(): "+matcher.matches());
System.out.println("lookingAt(): "+matcher2.lookingAt());
}
}

替换方法

  1. public Matcher appendReplacement(StringBuffer sb, String replacement)
    实现非终端添加和替换步骤。
  2. public StringBuffer appendTail(StringBuffer sb)
    实现终端添加和替换步骤。
  3. public String replaceAll(String replacement)
    替换模式与给定替换字符串相匹配的输入序列的每个子序列。
  4. public String replaceFirst(String replacement)
    替换模式与给定替换字符串匹配的输入序列的第一个子序列。
  5. public static String quoteReplacement(String s)
    返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement 方法一个字面字符串一样工作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches
{
private static String REGEX = "dog";
private static String INPUT = "The dog says meow. " +
"All dogs say meow.";
private static String REPLACE = "cat";

public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
// get a matcher object
Matcher m = p.matcher(INPUT);
INPUT = m.replaceAll(REPLACE);
System.out.println(INPUT);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches
{
private static String REGEX = "a*b";
private static String INPUT = "aabfooaabfooabfoobkkk";
private static String REPLACE = "-";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
// 获取 matcher 对象
Matcher m = p.matcher(INPUT);
StringBuffer sb = new StringBuffer();
while(m.find()){
m.appendReplacement(sb,REPLACE);
}
m.appendTail(sb);
System.out.println(sb.toString());
}
}

4 String自带的正则表达式功能

见String