正则表达式
正则表达式
1.概念
为什么学习正则表达式?
Java提供处理文本问题的技术,正则表达式(Regular Expression)是对字符串执行模式匹配的技术
2.了解正则表达式
package com.mf.study;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author:mufan
* @Date: 2022/06/11/10:06
* @Description: 体验正则表达式
*/
public class Regexp_1 {
public static void main(String[] args) {
//编写爬虫,从百度页面得到如下文本
String content = "牟帆1997年农历6月29出生,当晚屋外电闪雷鸣,狂风骤起,刮了3000分钟。500次电闪雷鸣,显示这这个孩子的不凡!";
//1. \d表示任意字符
String regStr = "(\\d\\d)(\\d\\d)";
//2.创建模式对象(正则表达式)
Pattern compile = Pattern.compile(regStr);
//3.创建匹配器
Matcher matcher = compile.matcher(content);
//4.开始匹配
/**
* matcher.find() 完成任务
* 1. 根据指定的规则,定位满足规则的子字符串(比如1997)
* 2.找到后,将 子字符串的开始的索引记录在 matcher 对象中 int[] groups 属性中
* groups[0]=2;把 该子字符串的结束的索引+1的值 记录到groups[1]=6中
* 3. 同时记录oldLast值 字符串的结束的索引+1的值 即6;即下次执行find方法时,从oldLast的值4 开始匹配
*
*分组:比如 (\d\d)(\d\d),正则表达式中有() 表示分组
* 例如:根据指定规则,定位满足规则的子字符串(比如(19)(97))
* (1)groups[0] = 2,把该子字符串的结束索引 +1 groups[1] = 6
* (2) 第一组()匹配到的子字符串:groups[2] = 2 ,groups[3] = 4
* (3)第二组()匹配到的子字符串:groups[4] = 4 , groups[5] = 6
* 更多组。。。
*
* 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();
* }
*
* 1.根据 group[0]=2 和 group[1]=6 记录的位置。 从content中开始截取子字符串,并返回
*
* 如果再次执行find方法,从6开始匹配
*
*
*/
while(matcher.find()){
/*
如果匹配规则有分组
matcher.group(0)-----匹配到的子字符串
matcher.group(1)-----匹配到的子字符串的第一组
matcher.group(2)-----匹配到的子字符串的第二组
。。。。。不能越界
*/
System.out.println("匹配出所有4个任意数字:"+matcher.group(0));//1997 3000
System.out.println("匹配到的第一组:"+matcher.group(1));//19
System.out.println("匹配到的第二组:"+matcher.group(2));//87
}
}
}
3.正则表达式的语法
(1)元字符
元字符按功能分为:
(1)限定符
(2)选择匹配符
(3)分组组合和反向引用符
(4)特殊字符
(5)字符匹配符
(6)定位符
元字符的转义符:\
什么情况下会用到转义符:* + ( ) $ / \ ? [ ] ^
I 字符匹配符
| 符号 | 符号 | 示例 | 解释 | 匹配输入 |
|---|---|---|---|---|
| [ ] | 可接收的字符列表 | [efgh] | e、f、g、h中的任意一字符 | e、f、g、h |
| [^] | 不可接收的字符列表 | [^abc] | 除a、b、c外任意一字符,包含数字和特殊字符 | d、#、2、... |
| - | 连字符 | A-Z | 任意单个大写字母 | A、D、... |
| . | 匹配除 \n 以外的任何字符 | a..b | 以 a 开头,b结尾,中间包括2个任意字符的长度为4的字符串 | asdb、a#sb、... |
| \\d | 匹配单个数字字符,相当于[0-9] | \\d{3}(\\d) | 包含3个或4个字符串 | 231、3445 |
| \\D | 匹配单个非数字字符,相当于[^0-9] | \\D(\\d)* | 以单个非数字字符开头,后接任意个数字字符串 | a122zsxz、#12dssd |
| \\w | 匹配单个数字、大小写字母字符。相当于[0-9a-zA-Z] | \\d{3}\\w | 以3个数字字符开头,长度为7的数字字母字符串 | 234abcd、12345Pe |
| \\W | 匹配单个非数字、大小写字母字符,相当于[^0-9a-zA-Z] | \\W+\\d | 以至少一个非数字字母字符串开头,两个数字字符字符串结尾 | #29、#@……45 |
Java 正则表达式默认是区分到小写
不区分大小写第一种方法:
(?i)abc 表示abc都不区分大小写
a(?i)bc 表示bc不区分大小写
a((?i)b)c 表示b不区分大小写
不区分大小写第二种方法:
//创建Pattern对象时,表示匹配对象时字母是不区分大小写的 Pattern compile = Pattern.compile(regexp,Pattern.CASE_INSENSITIVE);
案例
package com.mf.study;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author:mufan
* @Date: 2022/06/11/9:50
* @Description: 演示字符匹配的使用
*/
public class Test {
public static void main(String[] args) {
String content = "a11c8abc";
// String regexp = "[a-z]";//匹配 a-z 任意一个字符
// String regexp = "[A-Z]";//匹配 A-Z 任意一个字符
// String regexp = "abc";//匹配 abc 字符串(默认区分大小写)
// String regexp = "(?i)abc";//匹配 abc 字符串(不区分大小写)
// String regexp = "[0-9]";//匹配 0-9 任意一个字符
// String regexp = "[^a-z]";//匹配 不在 a-z 任意一个字符
// String regexp = "[^0-9]";//匹配 不在 0-9 任意一个字符
// String regexp = "[abc]";//匹配 在a、b、c中 任意一个字符
// String regexp = "[^abc]";//匹配 不在a、b、c中 任意一个字符
// String regexp = "\\w";//匹配 字母、数字、下划线 任意一个字符
// String regexp = "\\W";//匹配 除字母、数字、下划线之外 任意一个字符
// String regexp = "\\s";//匹配 空白字符(空格,制表符等) 任意一个字符
// String regexp = "\\S";//匹配 除空白字符(空格,制表符等)以外 任意一个字符
String regexp = ".";//匹配 \n之外的所有字符,如果匹配.本生要用转义字符 \\.
Pattern compile = Pattern.compile(regexp);
Matcher matcher = compile.matcher(content);
while(matcher.find()){
System.out.println("匹配到:"+matcher.group(0));//a c
}
}
}
II 选择匹配符
| 符号 | 符号 | 示例 | 解释 | 匹配输入 |
|---|---|---|---|---|
| | | 匹配“|”之前或之后的表达式 | ab|cd | ab|cd | ab、cd |
package com.mf.study;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author:mufan
* @Date: 2022/06/11/14:13
* @Description: 选择匹配符
*/
public class Test1 {
public static void main(String[] args) {
String content = "timo 提莫 提 莫";
String regexp = "ti|莫";
//创建Pattern对象
Pattern compile = Pattern.compile(regexp);
//创建匹配器
Matcher matcher = compile.matcher(content);
while(matcher.find()){
System.out.println("找到:"+matcher.group(0));
}
}
}
III 限定符
| 符号 | 含义 | 示例 | 说明 | 匹配输入 |
|---|---|---|---|---|
| * | 指定字符重复0次或n次(无要求) | (abc)* | 仅包含任意个abc的字符串,等效于\w* | abc、sdsad |
| + | 指定字符重复1次或n次(至少一次) | m+(abc)* | 至少一个m开头,后接任意个abc字符串 | m、mabc、msdsabc、msdsftabcabc |
| ? | 指定字符重复0次或1次(最多1次) | m+abc? | 至少一个m开头,后接最多一个abc字符串 | m、mabc、msdsabc |
| 只能输入n个字符 | [abcd] | 由a、b、c、d中字母组成任意长度为3的字符串 | abc、dbc、adc | |
| 指定至少n个匹配 | [abcd] | 由abcd中字母组成的任意长度不小于3的字符串 | aab、bdc、aabdc | |
| 指定至少 n 个但不多于 m 个匹配 | [abcd] | 由abcd中字母组成的任意长度不小于3,不大于5的字符串 | abc、abcd、aaaa、bcdab |
package com.mf.study;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author:mufan
* @Date: 2022/06/11/14:36
* @Description:演示限定符的使用
*/
public class Test2 {
public static void main(String[] args) {
String content ="11111111333243";
// String regexp = "a{3}";// 表示匹配 aaa 的字符
// String regexp = "1{4}";// 表示匹配 1111 的字符
// String regexp = "\\d{2}";// 表示匹配 2位任意字符串
// String regexp = "a{3,4}";// 表示匹配 aaa 或 aaaa (贪婪匹配,尽量匹配多的)
// String regexp = "\\d{2,5}";// 表示匹配 2-5位数字字符串 (贪婪匹配,尽量匹配多的)
// String regexp = "1+";// 表示匹配 一个1 或 多个 1
// String regexp = "1*";// 表示匹配 0个1 或 多个 1
String regexp = "a1?";// 表示匹配 a 或 a1
Pattern compile = Pattern.compile(regexp);
Matcher matcher = compile.matcher(content);
while(matcher.find()){
System.out.println("找到:"+ matcher.group(0));
}
}
}
IIII 定位符
| 符号 | 含义 | 示例 | 说明 | 匹配输入 |
|---|---|---|---|---|
| ^ | 指定起始字符 | [1]+[a-z]* | 以至少1个数字开头,后接任意个小写字母的字符串 | 123、6aa、555edf |
| $ | 指定结束字符 | [2]\\-[a-z]+$ | 以1个数字开头后连接字符"-",并以至少1个小写字母结尾的字符串 | 1-a |
| \\b | 匹配目标字符串的边界 | han\\b | 这里说的字符串的边界指的是子串间有空格,或者是目标字符串的结束位置 | |
| \\B | 匹配目标字符串的非边界 | han\\B | 和\b的含义刚刚相反 |
package com.mf.study;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author:mufan
* @Date: 2022/06/11/15:16
* @Description:演示定位符的使用
*/
public class Test3 {
public static void main(String[] args) {
String content = "123abc cd bc";
//以至少1个数字开头,后接任意个小写字母的字符串
// String regexp = "^[0-9]+[a-z]*";
//至少1个数字开头,必须以至少一个小写字母结束
// String regexp = "^[0-9]+[a-z]+$";
// String regexp = "c\\b"; //匹配边界(该字符串最后,或空格后子字符串的最后)c ------c c
String regexp = "c\\B"; //匹配边界(该字符串开头,或空格后子字符串的开头)c ------c
Pattern compile = Pattern.compile(regexp);
Matcher matcher = compile.matcher(content);
while(matcher.find()){
System.out.println("找到:"+matcher.group(0));
}
}
}
IIIII 分组
| 常用分组构造形式 | 说明 |
|---|---|
| () | 非命名捕获 |
| (? |
命名捕获 |
package com.mf.study;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author:mufan
* @Date: 2022/06/11/15:38
* @Description:分组
*/
public class Test4 {
public static void main(String[] args) {
String content = "moufan s3w423 df55f4fan";
String regexp = "(?<g1>\\d)(\\d)";//匹配2位数
Pattern compile = Pattern.compile(regexp);
Matcher matcher = compile.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));
}
}
}
浙公网安备 33010602011771号