文章目录
快速入门
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/4 16:25
* @Description: 体验正则表达式
*/
public class Regexp_ {
@Test
public void test1(){
// String content="2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布," +
// "几周后其获得了Apple公司Mac OS X的工业标准的支持。2001年9月24日," +
// "J2EE1.3发布。2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升" +
// ",与J2SE1.3相比,其多了近62%的类和接口。在这些新特性当中,还提供了广泛的XML支持、" +
// "安全套接字(Socket)支持(通过SSL与TLS协议)、全新的I/OAPI、正则表达式、日志与断言。" +
// "2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性," +
// "J2SE 1.5更名为Java SE 5.0(内部版本号1.5.0),代号为“Tiger”,Tiger包含了从1996年发布" +
// "1.0版本以来的最重大的更新,其中包括泛型支持、基本类型的自动装箱、改进的循环、枚举类型、格式化I/O及可变参数。";
//百度热搜 代码简化后
String content =
"<div class=\"FYB_RD\"><div class=\"cr-title c-gap-bottom-xsmall\" " +
"data-click=\"true\" title=\"百度热搜\"><a class=\"c-color-t opr-toplist1-title_1LgpS\" " +
"<a target=\"_blank\" title=\"考生:3年的数学难题都在卷子里\" href=\"https://top.baidu.co" +
"<a target=\"_blank\" title=\"湖北考生请枪手代答?当地辟谣\" href=\"/s?wd=%E6%B9%96%E5%8C%97%E8%80%83" +
"<a target=\"_blank\" title=\"成都考生提前一小时答完数学题\" href=\"/s?wd=%E6%88%90%E9%83%BD%E8%8";
//提取文章中的所有的英文单词
//(1) 传统方法,使用遍历方式,代码量大,效率不高
//(2) 正则表达式
//1. 创建Pattern对象,
//提取文章中的所有的英文单词
//Pattern pattern = Pattern.compile("[a-zA-Z]+");
//提取文章中的所有的数字
//Pattern pattern = Pattern.compile("[0-9]+");
//提取文章中的所有的英文单词和数字
//Pattern pattern = Pattern.compile("([a-zA-Z]+)|([0-9]+)");
//提取百度热搜的标题
Pattern pattern = Pattern.compile("<a target=\"_blank\" title=\"(\\S*)\"");
//2. 创建匹配器对象
// 理解 matcher 匹配器按照pattern模式对象,到content文本中去匹配
// 找到则返回true, 否则返回false
Matcher matcher = pattern.matcher(content);
//3. 可以开始循环匹配
while(matcher.find()){
//匹配内容,文本,放到 matcher.group(0)
System.out.println("找到:" + matcher.group(1));
}
}
}
学习正则表达式可以快速验证邮箱格式、手机格式等
正则表达式是对字符串执行模式匹配的技术
正则表达式基本语法
从功能上看,共有六大类元字符
转义号 \
\ 符号说明:在我们使用正则表达式去检索某些特殊字符的时候,需要用到转义符号,否则检索不到结果。如下所示:
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/8 22:29
* @Description: 演示转义符号的使用
*/
public class Regexp_02 {
@Test
public void test() {
String content = "abc()def.123(";
//匹配 ( => \\(
//匹配 . => \\.
Pattern pattern = Pattern.compile("\\.");
//2. 创建匹配器对象
// 理解 matcher 匹配器按照pattern模式对象,到content文本中去匹配
// 找到则返回true, 否则返回false
Matcher matcher = pattern.matcher(content);
//3. 可以开始循环匹配
while (matcher.find()) {
//匹配内容,文本,放到 matcher.group(0)
System.out.println("找到:" + matcher.group(0));
}
}
}
1. 字符匹配符
符号 | 含义 | 示例 | 解释 |
---|---|---|---|
[ ] | 可接收的字符列表 | [efgh] | e/f/g/h 中的任何一个字符 |
[^] | 不接收的字符列表 | [^abc] | 除 a、b、c之外的任意一个字符,包括数字和特殊符号 |
- | 连字符 | A-Z | 任意单个大写字母 |
. | 匹配除\n以外的任何字符 | a…b | 以a开头,以b结尾,中间2个任意 如 aabb,aa1b,a23b,a#%b |
\\d | 匹配单个数字字符,等价于[0-9] | \\d{3}(\\d)? | 包含3个、4个数字的字符串 如 123,1234 |
\\D | 匹配单个非数字字符,等价于[^0-9] | \\D(\\d)* | 以非数字开头,后接任意个数字字符串 如 a123,a |
\\w | 匹配单个数字、大小写字母字符、下划线,等价于[0-9a-zA-Z_] | \\d{3}\\w{4} | 以3个数字开头,长度为7的数字字符串 如 123abcd,12345PR |
\\W | 匹配单个非数字、大小写字母字符,等价于[^0-9a-zA-Z_] | \\W+\\d{2} | 以至少1个非数字字母字符开头,2个数字结尾的字符串 如 #12,#A#12 |
\\s | 匹配任何空白字符(空格、制表符) | ||
\\S | 匹配任何非空白字符,与\\s相反 |
示例代码:
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Regexp_03 {
@Test
public void test() {
String content = "abcdefABC. 123(";
//String regStr= "[a-z]"; //匹配 a-z之间的任意一个字符
//String regStr= "[^a-z]"; //匹配 不在a-z之间的任意一个字符
//String regStr= "abc"; //匹配 abc 默认区分大小写
//(?i)abc 表示 abc 都不区分大小写
//a(?i)bc 表示 bc 不区分大小写
//a((?i)b)c 表示只有 b 不区分大小写
//还可以写 Pattern pattern = Pattern.compile(regStr,Pattern.CASE_INSENSITIVE); 设置不区分
//String regStr = "(?i)abc";
//String regStr = "[A-Z]"; //匹配 A-Z 之间的任意一个字符
//String regStr = "[^A-Z]"; //匹配 不在A-Z 之间的任意一个字符
//String regStr = "[0-9]"; //匹配 0-9 之间的任意一个字符
//String regStr = "[^0-9]"; //匹配 不在0-9 之间的任意一个字符
//String regStr = "\\s"; //匹配空格,制表符
String regStr = "\\S"; //匹配非空格,非制表符
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到:" + matcher.group(0));
}
}
}
2. 选择匹配符
符号 | 含义 | 示例 | 解释 |
---|---|---|---|
| | 匹配’|'之前或之后的表达式 | ab|bc | ab或者bc |
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/9 7:22
* @Description: 选择匹配符
*/
public class Regexp_04 {
@Test
public void test() {
String content = "abcdacdv";
String regStr = "ab|cd"; //
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到:" + matcher.group(0));
}
}
}
3. 限定符
符号 | 含义 | 示例 | 解释 |
---|---|---|---|
* | 指定字符重复0次或n次 | (abc)* | 仅包含任意个abc的字符 如 abc、abcabcabc |
+ | 指定字符重复1次或n次 | m+(abc)* | 以至少1个m开头,后接任意个abc的字符 如 m、mabc、mabcabcabc |
? | 指定字符重复0次或1次 | m+abc? | 以至少1个m开头,后接ab或abc的字符串 如mab、mabc、mmab、mmabc |
{n} | 只能输入n个字符 | [abcd]{3} | 由abcd中的字母组成的任意长度为3的字符串 如abc、adc、acd |
{n,} | 指定至少n个字符 | [abcd]{3,} | 由abcd中的字母组成的任意长度不小于3的字符串 如abc、adcc、acdasc |
{n,m} | 指定至少n个但不多于m个字符 | [abcd]{3,5} | 由abcd中的字母组成的任意长度不小于3,不大于5的字符串 如abc、adcc、acdas |
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/9 7:22
* @Description: 限定符
*/
public class Regexp_05 {
@Test
public void test() {
String content = "a1111111aaaaa";
//a{3},1{4},\\d{2}
//String regStr = "a{3}"; // 匹配 aaa
//String regStr = "1{4}"; // 匹配 1111
//String regStr = "\\d{2}"; // 匹配 11、11、11 任意两个数字
//a{3,4},1{4,5},\\d{2,5}
//细节:java匹配默认贪婪匹配,尽可能匹配多的
//String regStr="a{3,4}"; //理论上匹配 aaa 或 aaaa ,实际匹配 aaaa
//String regStr="1{4,5}"; //理论上匹配 1111 或 11111 ,实际匹配 11111
//String regStr="\\d{2,5}"; //理论上匹配 2位,3位,4位,5位数字 ,实际匹配 11111,11
//1+
//String regStr="1+"; //理论上匹配 1个1或n个1 ,实际匹配 1111111 ,符合贪婪匹配
//String regStr="\\d+"; //理论上匹配 1个数字或n个数字 ,实际匹配 1111111
//1*
//String regStr="1*"; //理论上匹配 0个1或n个1
//?
String regStr="a1?"; //理论上匹配 a 或 a1
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到:" + matcher.group(0));
}
}
}
4. 定位符
符号 | 含义 | 示例 | 解释 |
---|---|---|---|
^ | 指定起始字符 | ^[0-9]+[a-z]* | 以至少1个数字开头,后接任意个小写字母的字符 如123,123a |
$ | 指定结束字符 | ^[0-9]+\\-[a-z]+$ | 以至少1个数字开头,后接- 再加上至少1个小写字母的字符 如 123-abc |
\\b | 匹配目标字符串的边界 | ma\\b | maenma ma 会匹配第二、三个ma |
\\B | 匹配目标字符串的非边界 | ma\\B | 与\\b相反 maenma ma 会匹配第一个ma |
{n,} | 指定至少n个字符 | [abcd]{3,} | 由abcd中的字母组成的任意长度不小于3的字符串 如abc、adcc、acdasc |
{n,m} | 指定至少n个但不多于m个字符 | [abcd]{3,5} | 由abcd中的字母组成的任意长度不小于3,不大于5的字符串 如abc、adcc、acdas |
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/9 7:22
* @Description: 定位符
*/
public class Regexp_06 {
@Test
public void test() {
String content = "123-abc";
//以至少1个数字开头,至少一个小写字母结束的字符串
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));
}
}
@Test
public void test2(){
String content = "maenming enma enmingma";
//表示匹配边界的ma[这里的边界是指:被匹配的字符串最后, 也可以是空格的子字符串的后面]
//String regStr="ma\\b"; //找到后两个ma
// \\B 与 \\b相反
String regStr="ma\\B"; //找到第一个ma
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到:" + matcher.group(0));
}
}
}
5. 分组组合 、反向引用符
- 常用分组
常用分组构造形式 | 说明 |
---|---|
(pattern) | 非命名捕获。捕获匹配的子字符串。编号为0的第一个捕获是由整个正则表达式模式匹配的文本,其他捕获结果则根据左括号的顺序从1开始自动编号 |
(?<name>pattern) | 命名捕获。捕获匹配的子字符串。匹配的分组可以按照名字来访问也可以按照编号 |
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/9 7:22
* @Description: 捕获分组
*/
public class Regexp_07 {
@Test
public void test() {
String content = "1234abcd2234";
//matcher.group(0) 存放匹配到的全部子串
//matcher.group(1) 存放第一个分组
//......
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("第1个分组:"+matcher.group(1));
System.out.println("第2个分组:"+matcher.group(2));
System.out.println("第3个分组:"+matcher.group(3));
}
}
@Test
public void test2(){
String content = "1234abcd2234";
//matcher.group(0) 存放匹配到的全部子串
//matcher.group(1) 存放第一个分组
//......
//还可以按照matcher.group("g1") 获取分组
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("分组1:" + matcher.group(1));
System.out.println("分组1(name):" + matcher.group("g1"));
System.out.println("分组2:" + matcher.group(2));
System.out.println("分组2(name):" + matcher.group("g2"));
}
}
}
- 特殊分组(不能按group(编号) 取值)
常用分组构造形式 | 说明 |
---|---|
(?:pattern) | 匹配pattern但不捕获该匹配的子表达式,即他是一个非捕获匹配 ,如 industr(?:y|ies) 等价于 industry|industries |
(?=pattern) | 一个非捕获匹配 ,如 windows(?=95|98|2000) 匹配的是 windows 2000 的windows 而不匹配windows 3.1的windows |
(?!pattern) | 一个非捕获匹配 ,如 windows(?!95|98|2000) 匹配的是 windows 3.1 的windows 而不匹配windows 2000的windows |
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/9 7:22
* @Description: 非捕获分组
*/
public class Regexp_08 {
//(?: )
@Test
public void test() {
String content = "hi小明同学 hi小李同学 hi小黄同学";
//String regStr="小明同学|小李同学|小黄同学";
//等价于
String regStr="小(?:明|李|黄)同学";//不能捕获 matcher.group(1)
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到:" + matcher.group(0));
}
}
//(?= )
@Test
public void test2() {
String content = "hi同学小明 hi同学小李 hi同学小黄";
String regStr="同学(?=小明|小李)";//匹配到的是小明or小李 的 "同学"
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到:" + matcher.group(0));
}
}
//(?! )
@Test
public void test3() {
String content = "hi同学小明 hi同学小李 hi同学小黄";
String regStr="同学(?!小明|小李)";//匹配到的不是小明or小李 的 "同学"
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到:" + matcher.group(0));
}
}
}
非贪婪匹配
:
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/9
* @Description: 非贪婪匹配
*/
public class Regexp_09 {
//(?: )
@Test
public void test() {
String content = "a11111111aaa";
//String regStr="\\d+";//默认贪婪匹配 返回 11111111
String regStr="\\d+?"; //非贪婪匹配 返回 1,1,1,1,1,1,1,1
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到:" + matcher.group(0));
}
}
}
6.特殊字符
略
三个常用类
java.util.regex 包下主要包括3个类 Pattern 、Matcher、PatternSyntaxException
Pattern
pattern对象是一个正则表达式对象。Pattern类没有公共构造方法。要创建一个Pattern对象,调用其公共静态方法,返回一个Pattern对象,该方法接受一个正则表达式作为它的第一个参数,比如:Pattern pattern = Pattern.compile(String regex)。
import org.junit.Test;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/11 10:38
* @Description: 演示matches方法,用于整体匹配,在验证输入的字符串是否满足条件使用,用于简化开发
*/
public class PatternMethod {
@Test
public void test(){
String content = "hello world";
//String regStr="hello"; //false
String regStr = "hello.*"; //true
boolean matches = Pattern.matches(regStr, content);
System.out.println("整体匹配= "+matches);
}
}
Matcher
Matcher 对象是对输入字符串进行解释和匹配的引擎。与Pattern类一样,Matcher也没有公共构造方法。你需要调用Pattern对象的matcher()返回一个Matcher对象。
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/11 13:44
* @Description: Matcher中的方法
*/
public class MatcherMethod {
@Test
public void test(){
String content = "hello world ,hello mei_ming";
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("找到:" + matcher.group(0));
System.out.println("找到:"+content.substring(matcher.start(),matcher.end())); //等同于 group(0)
}
}
//整体匹配
@Test
public void test2(){
String content = "hello world ,hello mei_ming";
String regStr="hello.*";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
//整体匹配
System.out.println(matcher.matches()); //true
}
//替换
@Test
public void test3(){
String content = "hello world ,hello mei_ming";
//替换成regStr的值
String regStr="hello";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
String newContent = matcher.replaceAll("hi");
System.out.println("返回的字符串:"+newContent);
System.out.println("原来的字符串:"+content);
}
}
PatternSyntaxException
PatternSyntaxException是一个非强制异常类,他表示一个正则表达式模式中的语法错误
反向引用
- 分组:用圆括号组成一个比较复杂的匹配模式,称为一个分组或一个子表达式
- 捕获:把正则表达式中的分组内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右,以分组的左括号为标志,第一个出现分组为1…,整体分组为0
- 反向引用:圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,成为反向引用,内部反向引用 \\分组号 ,外部反向引用: $分组号
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/11 14:05
* @Description: 反向引用
*/
public class Regexp_11 {
@Test
public void test(){
String content = "abc1221 33abcd144444acbc 5566 ";
//匹配两个连续相同的数
//String regStr = "(\\d)\\1";
//匹配五个连续相同的数
//String regStr = "(\\d)\\1{4}";
//匹配abba这样的四位数
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));
}
}
@Test
public void test2(){
String content = "12345-333999666";
//匹配 12345-333999666 这样的数 -左边5位数随机 -右边9位数 aaabbbccc
String regStr = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到:" + matcher.group(0));
}
}
}
原理
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/8 20:59
* @Description: 正则底层原理
*/
public class RegTheory {
//匹配无分组的情况
@Test
public void test1(){
String content="2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。2001年9月24日," +
"J2EE1.3发布。2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升" +
",与J2SE1.3相比,其多了近62%的类和接口。在这些新特性当中,还提供了广泛的XML支持、" +
"安全套接字(Socket)支持(通过SSL与TLS协议)、全新的I/OAPI、正则表达式、日志与断言。" +
"2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性," +
"J2SE 1.5更名为Java SE 5.0(内部版本号1.5.0),代号为“Tiger”,Tiger包含了从1996年发布" +
"1.0版本以来的最重大的更新,其中包括泛型支持、基本类型的自动装箱、改进的循环、枚举类型、格式化I/O及可变参数。";
//1. 创建Pattern对象,
//提取文章中的四个数字
// \\d 表示一个任意的数字
Pattern pattern = Pattern.compile("\\d\\d\\d\\d");
//2. 创建匹配器对象
// 理解 matcher 匹配器按照pattern模式对象,到content文本中去匹配
// 找到则返回true, 否则返回false
Matcher matcher = pattern.matcher(content);
//3. 可以开始循环匹配
/**
* matcher.find() 完成的任务
* 1. 根据指定的规则,定位满足规则的子字符串(比如2000)
* 2. 找到后,将 子字符串的开始索引记录到matcher对象属性 int[] groups; 中
* 赋值 groups[0] = 0 即开始位置
* groups[1] = 4 即子字符串结束位置 +1
* 3. 同时记录oldLast的值为4,作为下一次执行find的位置
*
* 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();
* }
*
* 1. getSubSequence 方法 返回从 groups[group * 2]到 groups[group * 2 + 1] 的子串 ,即group=0
* 根据groups[0]=0,groups[1]=4 的记录的位置,从content开始截取子字符串
* 就是[0,4)的位置上的字符
*
* 若再次执行, groups[0] = 65 , groups[1] = 69 , ordLast = 69
* getSubSequence(65,69) 返回 2001
*/
while(matcher.find()){
//匹配内容,文本,放到 matcher.group(0)
System.out.println("找到:" + matcher.group(0));
}
}
//有分组的情况
@Test
public void test2(){
String content="2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。2001年9月24日," +
"J2EE1.3发布。2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升" +
",与J2SE1.3相比,其多了近62%的类和接口。在这些新特性当中,还提供了广泛的XML支持、" +
"安全套接字(Socket)支持(通过SSL与TLS协议)、全新的I/OAPI、正则表达式、日志与断言。" +
"2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性," +
"J2SE 1.5更名为Java SE 5.0(内部版本号1.5.0),代号为“Tiger”,Tiger包含了从1996年发布" +
"1.0版本以来的最重大的更新,其中包括泛型支持、基本类型的自动装箱、改进的循环、枚举类型、格式化I/O及可变参数。";
//1. 创建Pattern对象,
//提取文章中的四个数字
// \\d 表示一个任意的数字
Pattern pattern = Pattern.compile("(\\d\\d)(\\d\\d)");
//2. 创建匹配器对象
// 理解 matcher 匹配器按照pattern模式对象,到content文本中去匹配
// 找到则返回true, 否则返回false
Matcher matcher = pattern.matcher(content);
//3. 可以开始循环匹配
/**
* matcher.find() 完成的任务
* 1. 根据指定的规则,定位满足规则的子字符串(比如2000)
* 2. 找到后,将 子字符串的开始索引记录到matcher对象属性 int[] groups; 中
* 2.1 赋值 groups[0] = 0 即开始位置
* groups[1] = 4 即子字符串结束位置 +1
*
* 2.2 接着赋值 groups[2]=0, groups[3]=2 记录第一个分组()匹配到的字符串
* 2.3 接着赋值 groups[4]=2, groups[5]=4 记录第二个分组()匹配到的字符串
*
* 3. 同时记录oldLast的值为4,作为下一次执行find的位置
*
* 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();
* }
*
* 1. getSubSequence 方法 返回从 groups[group * 2]到 groups[group * 2 + 1] 的子串 ,
* 若group=0时 ,根据groups[0]=0,groups[1]=4 的记录的位置,从content开始截取子字符串
* 就是[0,4)的位置上的字符
* 若group=1时 ,就是groups[2]=0,groups[3]=2 的记录的位置,也就是 [0,2)
* 若group=2时 ,就是groups[4]=2,groups[5]=4 的记录的位置,也就是 [2,4)
*
*/
while(matcher.find()){
//小结:
//1. 如果正则表达式有() 即 有分组
//2. 取出字符串如下
//3. group(0) : 取 匹配到的字符串
//4. group(1) : 取 第一组的字符串
//5. group(2) : 取 第二组的字符串
//6. 越界则报错 throw new IndexOutOfBoundsException("No group " + group);
System.out.println("找到:" + matcher.group(0));
System.out.println(" 找到:" + matcher.group(1));
System.out.println(" 找到:" + matcher.group(2));
}
}
}
应用实例
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: mei_ming
* @DateTime: 2022/6/11 9:34
* @Description: 正则表达式应用实例
*/
public class Regexp_10 {
@Test
public void test(){
//汉字
//String content="中文汉字"; //满足要求
//String regStr="^[\u0391-\uffe5]+$";
//邮政编码
//要求:是1-9开头的一个6位数
//String content = "330324";
//String regStr="^[1-9]\\d{5}$";
// QQ号
//要求:是1-9开头的一个5位-10位数
//String content = "1791666142";
//String regStr="^[1-9]\\d{4,9}$";
// 手机号
//要求:是以13,14,15,18 开头的11位数
String content = "13916661421";
String regStr="^1[3|4|5|8]\\d{9}$";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if(matcher.find()){
System.out.println("满足要求");
}else{
System.out.println("不满足要求");
}
}
@Test
public void test2(){
//URL验证
//String content = "https://baike.baidu.com/item/Java/85979?fr=aladdin";
String content = "http://tgxmf.yxaad.com/school/dl/9607/" +
"?source=shyx-pc&plan=3wanglianyu-DL&unit=dlzhancheng%EF%BC%8Bjavaxiangmu&" +
"keyword=javapeixunlingjichu&e_creative=58309754528&e_keywordid=393605165955&bd_vid=11917634435375433147";
/**
* 验证思路:
* 1. 匹配开头:^((https?)://) 可以是 http:// | https://
* 2. 然后通过 ([\w-]+\.)+[\w-]+ 匹配 baike.baidu.com
* 3. (\/[\w-?=&/%.#]*)?$ 匹配 /item/Java/85979?fr=aladdin
*/
String regStr="^((https?)://)([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if(matcher.find()){
System.out.println("满足要求");
}else{
System.out.println("不满足要求");
}
}
//测试 [.]
@Test
public void test3(){
String content = "hello.world";
//String regStr="."; //匹配所有
String regStr="[.]"; //匹配 .
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
System.out.println("找到:"+matcher.group(0));
}
}
//邮箱验证
//matches:整体匹配
@Test
public void test4(){
//只有1个@
//@前面是用户名,可以是a-zA-Z0-9_-字符
//@后面是域名,比如sohu.com souhu.com.cn
String content = "1791666142@qq.com";
String regStr= "^[\\w-]+@([a-zA-Z]+\\.)+[a-zA-Z]+$";
if(content.matches(regStr)){
System.out.println("符合");
}else{
System.out.println("不符合");
}
}
//判断数字
@Test
public void test5(){
//1. 验证整数和浮点数
//2. 正数和负数
//+1 √
//-1 √
//0.1 √
//12.21 √
//23 √
String content = "0.234";
String regStr= "^[-+]?([1-9]\\d*|0)(\\.\\d+)?$";
if(content.matches(regStr)){
System.out.println("符合");
}else{
System.out.println("不符合");
}
}
//验证URL 取协议、域名等
@Test
public void test6(){
//协议、域名、端口、资源
String content = "http://www.baidu.com:8080/admin/index.jsp";
String regStr= "^([a-zA-Z]+)://([a-zA-Z.]+):(\\d+)[\\w-/]*/([\\w.]+)$";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if(matcher.find()){
System.out.println("匹配成功:"+matcher.group(0));
System.out.println("协议:"+matcher.group(1));
System.out.println("域名:"+matcher.group(2));
System.out.println("端口:"+matcher.group(3));
System.out.println("资源:"+matcher.group(4));
}else{
System.out.println("不符合");
}
}
}
个人自学用笔记,欢迎纠错