三要素
- 字符串表达式
- Pattern模板对象
Matcher匹配器
public class RegexpDemo {
public static void main(String[] args) {
String regex = "regex";
String content = "content";
// 获取表达式对应的模板对象,区分大小写
Pattern pattern = Pattern.compile(regex);
// 获取表达式对应的模板对象,不区分大小写
Pattern caseInsensitivePattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
// 直接判断表达式是否整体匹配内容,相当于表达式前后强制加了定位符^$
boolean isMatch = Pattern.matches(regex, content);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
}
}
}
Matcher匹配器源码解析
public final class Matcher implements MatchResult {
/**
* 存储字符串索引值得容器
*/
int[] groups;
/**
* 最后一次匹配操作中匹配的对象的结束索引+1
*/
int oldLast = -1;
public boolean find() {
//源码...
}
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();
}
}
执行 find() 方法解析
匹配器根据模板对象的规则,定位满足规则的子字符串
- 将匹配的子字符串记录到
groups
中- 数组的默认值为-1
groups[0]
记录子字符串开始索引,groups[1]
和oldLast
记录子字符串的结束索引+1- 如果有分组,即表达式中设置了
()
,则groups[2]
记录分组1的开始索引,groups[3]
记录分组1的结束索引+1,groups[4]
记录分组2的开始索引,groups[5]
记录分组2的结束索引+1,如果有更多的分组,依此类推
在下次执行
find()
时,匹配器将从从oldLast
开始匹配执行 group(0) 方法解析
根据
groups[0]
和groups[1]
记录的索引位置截取字符串获得相应的子字符串- 字符串sub(截取)规则:
[groups[0], groups[1])
,包含groups[0]
,不包含groups[1]
- 参考字符串截取规则,可以理解
groups[1]
为什么记录的是子字符串的结束索引+1相关方法
| 方法 | 描述 | | —- | —- | | boolean find() | 尝试查找与该表达式匹配的输入序列的下一个子字符串 | | boolean find(int start) | 重置此匹配器,然后尝试查找匹配该表达式、从指定索引开始的输入序列的下一个子字符串 | | boolean matches() | 尝试将整个字符串与表达式匹配,相当于表达式前后强制加了定位符^$ | | boolean lookingAt() | 尝试从整个字符串的开头位置开始匹配表达式的匹配结果 | | int start() | 返回上次匹配子字符串初始索引 | | int start(int group) | 返回在上次的匹配操作期间,由给定组所捕获的子序列的初始索引 | | int end() | 返回上次匹配子字符串结束索引+1 | | int end(int group) | 返回在上次的匹配操作期间,由给定组所捕获子字符串结束索引+1 | | Matcher appendReplacement(StringBuffer sb, String replacement) | 实现非终端添加和替换步骤 | | StringBuffer appendTail(StringBuffer sb) | 实现终端添加和替换步骤 | | String replaceAll(String replacement) | 使用给定字符串替换表达式匹配的每个子字符串 | | String replaceFirst(String replacement) | 使用给定字符串替换表达式匹配的第一个子字符串 | | static String quoteReplacement(String s) | 返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement方法一个字面字符串一样工作 |
元字符
转义符
需要用到转义符的字符有:.*+()$/\?[]^{}
在Java中的转义符是\\
,其他语言是\
字符匹配符
Java的字符匹配符默认区分大小写,改变方式:
- 通过(?i)改为不区分大小写。例如
(?i)abc
可以匹配abc或ABC,a(?i)bc
可以匹配bc或BC,a(?)b)c
可以匹配b或B - 通过设置参数不区分大小写。例如
Pattern._compile(_regStr, Pattern._CASE_INSENSITIVE)_;
| 符号 | 定义 | 模板示例 | 示例说明 | 命中示例 | | —- | —- | —- | —- | —- | | [] | 可接收的字符列表 | [efgh] | e、f、g、h中的任意1个字符 | | | [^] | 不可接收的字符列表 | [^abc] | 除a、b、c之外的任意1个字符,包括数字和特殊符号 | | | - | 连字符 | A-Z | 任意1个大写字母 | | | . | 匹配除\n以外的任何字符,如果要匹配.本身需要使用\\. | a..b | 以a开头,b结尾,中间包括2个任意字符的长度为4的字符串 | aaab、aefb、a35b、a#b | | \\d | 匹配1个数字字符,相当于[0-9] | \\d{3}(\\d)? | 包含3个或4个数字的字符串 | 123、9876 | | \\D | 匹配1个非数字字符,相当于[^0-9] | \\D(\\d) | 以1个非数字字符开头,后接任意个数数字字符串 | a、A342 | | \\w | 匹配1个数字、大小写字母字符、下划线,相当于[0-9a-zA-Z] | \\d{3}\\w{4} | 以3个数字字符开头的长度为7的数字字母字符串 | 1_2 abcd、12345Ef | | \\W | 匹配1个非数字、大小写字母字符、下划线,相当于[^0-9a-zA-Z] | \\W+\\d{2} | 以至少1个非数字字母字符开头,2个数字字符结尾的字符串 | #29、#?@10 | | \\s | 匹配任何空白字符(空格,制表符等) | | | | | \\S | 匹配任何非空白字符 | | | |
选择匹配符
多个表达式之间的关系选择
符号 | 定义 | 模板示例 | 示例说明 | 命中示例 |
---|---|---|---|---|
| | 匹配”|”之前或之后的表达式 | ab|cd|ef | ab或cd或ef |
限定符
用于指定其前面的字符或组合项重复次数
符号 | 定义 | 模板示例 | 示例说明 | 命中示例 |
---|---|---|---|---|
* | 指定字符重复任意次 | (abc)* | 仅包含任意个abc的字符串 | abc、abcabcabc |
+ | 指定字符重复至少1次,默认贪婪匹配 | m+(abc)* | 以至少1个m开头,后接任意个abc的字符串 | m、mabc、mabcabc |
? | 指定字符重复最多1次 | m+abc? | 以至少1个m开头,后接最多一次c的字符 | m、mab、mabc、mmabc |
{n} | 指定字符重复n次 | [abcd]{3} | 由abcd中字母组成的任意长度为3的字符串 | aac、dbc、adc |
{n,} | 指定字符重复至少n次,默认贪婪匹配 | [abcd]{3,} | 由abcd中字母组成的任意长度不小于3的字符串 | aab、dbc、aaabdc |
{n,m} | 指定字符重复n次到m次,默认贪婪匹配 | [abcd]{3,5} | 由abcd中字母组成长度3到5的字符串 | abc、abcd、aaaaa、bcdab |
? | 当此字符紧随其他限定符之后使用时,匹配模式改为非贪婪匹配,即尽可能匹配短的字符串。 | o+? | 只匹配单个”o” | oooo |
定位符
规定要匹配的字符串出现的位置,比如在字符串的开始还是在结束的位置
符号 | 定义 | 模板示例 | 示例说明 | 命中示例 |
---|---|---|---|---|
^ | 指定起始字符 | ^[0-9]+[a-z]* | 以至少1个数字开头,后接任意个小写字母的字符串 | 123、6aa、555edf |
$ | 指定结束字符 | ^[0-9]\\-[a-z]+$ | 以1个数字开头后接连字符”-“,并以至少1个小写字母结尾的字符串 | 1-a |
\\b | 匹配目标字符串的边界 | ban\\b | 边界指的是字串间有空格,或目标字符串的结束位置 | bandaoban nnban |
\\B | 匹配目标字符串的非边界 | ban\\B | bandaoban nnban |
分组
捕获分组
构造形式 | 说明 |
---|---|
(pattern) | 非命名捕获。捕获匹配的子字符串。group(0)为第1个捕获结果,为整个正则表达式模板匹配的文本,其他捕获结果group(1)、group(2)等根据左括号的顺序开始自动编号 |
(? 或 (?’name’pattern) |
命名捕获。既可以用编号获取,也可以用命名获取。用于name的字符串不能包含任何标点符号,并且不能以数字开头 |
非捕获分组
非捕获分组匹配,不会存储到分组中,更经济,更节省资源,同时不可用group(1)等方式去捕获,否则会报错
构造形式 | 说明 |
---|---|
(?:pattern) | 此构造常用于替换(|)的分组形式。例如,”industr(?:y|ies)表达式”比”industry|industries”更经济 |
(?=pattern) | 此构造常用于匹配需要在明确范围内的分组形式。例如,”Windows(?=95|98|NT|2000)”匹配”Windows2000”中的”Windows”,但不匹配”Windows3.1”中的”Windows” |
(?!pattern) | 此构造常用于匹配需要在明确范围外的分组形式。例如,”Windows(?!95|98|NT|2000)”匹配”Windows3.1”中的”Windows”,但不匹配”Windows2000”中的”Windows” |
反向引用
当分组捕获后,分组号可以被反向引用,如果在表达式内部使用则采用”\分组号”的形式,如果在表达式外部使用则采用”$分组号”的形式。
构造形式 | 说明 |
---|---|
(pattern)\\1{4} | 连续匹配五个相同的子字符串 |
(pattern)(pattern)\\2\\1 | 第一个字符串与第四个子字符串相同,第二个子字符串与第三个子字符串相同 |
String类中使用正则表达式
相关方法
方法 | 说明 |
---|---|
String replaceAll(String regex, String replacement) | 替换符合表达式的子字符串 |
String[] split(String regex) | 按符合表达式的子字符串进行分割 |
boolean matches(String regex) | 判断整个字符串是否匹配表达式 |