欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 新车 > 正则表达式

正则表达式

2025/2/7 16:36:58 来源:https://blog.csdn.net/gaosw0521/article/details/141678306  浏览:    关键词:正则表达式

文章目录

  • 1 正则表达式基本介绍
  • 2 正则表达式语法
    • 2.1 元字符-转义号 \\\
    • 2.2 元字符-字符匹配符
    • 2.3 元字符-选择匹配符
    • 2.4 元字符-限定符
    • 2.5 元字符-定位符
    • 2.6 分组
  • 3 正则表达式三个常用类
    • 3.1 Pattern类的Matches方法
    • 3.2 Matcher类的常用方法
  • 4 分组、捕获、反向引用
  • 5 String类中使用正则表达式
    • 5.1 替换功能
    • 5.2 判断功能
    • 5.3 分割功能
  • 6 正则表达式使用案例
    • 6.1 验证电子邮箱格式是否合法
    • 6.2 验证手机号码是否合法
    • 6.3 验证URL格式是否合法
  • 7 正则表达式底层实现
  • 8 Reference

1 正则表达式基本介绍

正则表达式(Regular Expression),简单地说:正则表达式是对字符串执行模式匹配的技术。

一个正则表达式,就是用某种模式去匹配字符串的一个公式。

2 正则表达式语法

如果要想灵活的运用正则表达式,必须了解其中各种元字符的功能,元字符从功能上大致分为:

  • 限定符
  • 选择匹配符
  • 分组组合和反向引用符
  • 特殊字符
  • 字符匹配符
  • 定位符

2.1 元字符-转义号 \\

在我们使用正则表达式去检索某些特殊字符的时候,需要用到转义符号,否则检索不到结果,甚至会报错的。

需要用到转义符号的字符有以下:

. * + () $ / \ ? [ ] ^ { }

2.2 元字符-字符匹配符

符号含义示例解释匹配输入
[ ]可接收字符列表[abcd]a、b、c、d中任意1个字符a,b,c,d
[^]不接收字符列表[^abc]除a、b、c之外的任意一个字符d,1,#,…
-连字符a-z任意单个小写字母a,d,…
.匹配除\n以外的的任何字符a…b以a开头,b结尾,中间包括2个任意字符的长度为4的字符串a12b,aw@b,…
\\d匹配单个数字字符,相当于[0,9]\\d{3}(\\d)?包含3个或4个数字的字符串123,1234,…
\\D匹配单个非数字字符,相当于[ ^0-9]\\D(\\d)*以单个非数字字符开头,后接任意个数字字符串q,#,A123,…
\\w匹配单个数字、大小写字母、下划线,相当于[0-9a-zA-Z_]\\d{3}\\w{4}以3个数字开头的长度为7的数字字母字符串123abcd,12345ab,1234567
\\W匹配单个非数字、大小写字母、下划线字符,相当于[ ^0-9a-zA-Z]\\W+\\d{2}以至少1个非数字字母字符开头,2个数字字符结尾的字符串#12,#*&@90,…
\\s匹配任意空白字符(空格,制表符)\\s
\\S匹配任意非空白字符(空格,制表符)\\S

2.3 元字符-选择匹配符

符号含义示例解释匹配输入
|匹配”|“之前或之后的表达式ab|cdab或者cdab,cd

2.4 元字符-限定符

用于指定前面的字符和组合项连续出现多少次

符号含义示例解释匹配输入
*指定字符重复0次或n次(0到多)(abc)*仅包含任意个abc的字符串abc,abcabc,…
+指定字符重复1次或n次(1到多)A+(ab)*以至少1个A开头,后接任意个ab的字符串Aab,AAabab
?指定字符重复0次或1次(0到1)A+abc?以至少1个A开头,后接ab或abc的字符串Aab,AAabc
{n}只能输入n个字符[abcd]{3}由abcd中字母组成任意长度为3的字符串abc,acd,…
{n,}指定至少n个匹配[abcd]{3,}由abcd中字母组成任意长度不小于3的字符串aab,abcd,aabbcd
{n,m}指定至少n个但不多于m个匹配[abcd]{3,5}由abcd中字母组成任意长度不小于3,不大于5的字符串abc,abcd,aaaaa

2.5 元字符-定位符

符号含义示例解释匹配输入
^指定起始字符^ [0-9]+[a-z]*以至少1个数字开头,后接任意个小写字母的字符串123,1aa,22esf
$指定结束字符^ [0-9]\\-[a-z]+$以1个数字开头后接连字符”-“,并以至少1个小写字母结尾的字符串1-a,1-abc
\\b匹配目标字符串的边界abc\\b这里的字符串的边界指的是子串间有空格,或者是目标字符串的结束位置qwerabc
\\B匹配目标字符串的非边界abc\\B和\b的含义相反abcqwer

2.6 分组

常用分组构造形式说明
(pattern)非命名捕获。捕获匹配的子字符串。编号为0的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从1开始自动编号
(?pattern)命名捕获。将匹配的字符串捕获到一个组名或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号代替尖括号,例如(?’name‘)
(?:pattern)匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储以后使用的匹配。这对于用”or“字符(|)组合模式部件的情况很有用。例如,’industr(?:y|ies)‘是比’industry|industries‘更经济的表达式
(?=pattern)它是一个非捕获匹配。例如’Windows(?=95|98|NT|2000)匹配”Windows 2000“中的”Windows“,但不匹配”Windows 10“中的”Windows“
(?!pattern)该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串。它是一个非捕获匹配。例如’Windows(?=95|98|NT|2000)匹配”Windows 10“中的”Windows“,但不匹配”Windows 2000“中的”Windows“
package regularexpression;import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** @package: regularexpression* @description:分组* @author: Yunyang* @date: 2023/11/26  20:52* @version:1.0**/
public class RegExp07 {public static void main(String[] args) {String content = "helloworld s7789 n1189han";// String regStr = "(\\d\\d)(\\d\\d)";//匹配4个数字的字符串// String regStr = "(\\d\\d)(\\d)(\\d)";//匹配4个数字的字符串String regStr = "(?<g1>\\d\\d)(?<g2>\\d\\d)";//匹配4个数字的字符串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个分组[通过组名]:"+matcher.group("g1"));System.out.println("找到第2个分组:"+matcher.group(2));System.out.println("找到第2个分组[通过组名]:"+matcher.group("g2"));// System.out.println("找到第3个分组:"+matcher.group(3));}}
}

3 正则表达式三个常用类

java.util.regex包主要包括以下三个类:Pattern类、Matcher类和PatternSyntaxException类

  • Pattern类

pattern对象是一个正则表达式对象。Pattern类没有公共构造方法。要创建一个Pattern对象,调用其公共静态方法,它返回一个Pattern对象。

  • Matcher类

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

  • PatternSyntaxException类

PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式下的语法错误。

3.1 Pattern类的Matches方法

package regularexpression;import java.util.regex.Pattern;/*** @package: regularexpression* @description:matches方法,用于整体匹配,在研制输入的字符串是否满足条件使用* @author: Yunyang* @date: 2023/11/26  22:03* @version:1.0**/
public class PatternMethod {public static void main(String[] args) {String content = "hello world hello java,你好世界";String regStr = "hello.*";boolean matches = Pattern.matches(regStr, content);System.out.println("整体匹配 = " + matches);}
}

3.2 Matcher类的常用方法

package regularexpression;import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** @package: regularexpression* @description:Matcher类的常用的方法* @author: Yunyang* @date: 2023/11/26  22:10* @version:1.0**/
public class MatcherMethod {public static void main(String[] args) {String content = "hello world jack hello tom hello smitch 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()));}//整体匹配,常用于校验某个字符串是否满足某个规则System.out.println(matcher.matches());regStr = "world";pattern = Pattern.compile(regStr);matcher = pattern.matcher(content);String newcontent = matcher.replaceAll("世界");//注意:返回的字符串才是替换后的字符串 原来的 content 不变化System.out.println("newcontent = " + newcontent);System.out.println("content = " + content);}
}

4 分组、捕获、反向引用

  1. 分组

我们可以用圆括号组成一个比较复杂的匹配模式,那么一个圆括号的部分就可以看作是一个子表达式/一个分组

例如:(\\d\\d)(\\d\\d)中有两个分组

  1. 捕获

把正则表达式/分组匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左到右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。组0表示的是整个正则表达式。

例如:(\\d\\d)(\\d\\d)(\\d)中有三个分组,组0表示整个表达式:(\\d\\d)(\\d\\d),组1表示前一个圆括号的内容(\\d\\d),组2表示第二个括号的内容(\\d\\d),组3表示最后一个括号的内容

  1. 反向引用

圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,称之为反向引用,这种引用既可以是正则表达式内部,也可以是在正则表达式外部,内部反向引用**\\分组号**,外部反向引用**$分组号**

例如:匹配5个连续的相同数字:(\\d)\\1{4}

5 String类中使用正则表达式

5.1 替换功能

String 类 public String replaceAll(String regex,String replacement)

5.2 判断功能

String 类 public boolean matches(String regex){} //使用 Pattern 和 Matcher 类

5.3 分割功能

String 类 public String[] split(String regex)

package regularexpression;/*** @package: regularexpression* @description:String类中使用正则表达式* @author: Yunyang* @date: 2023/11/26  23:08* @version:1.0**/public class StringReg {public static void main(String[] args) {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及可变参数。";//使用正则表达式将JDK1.3和JDK1.4替换成JDKcontent = content.replaceAll("JDK1\\.3|JDK1\\.4","JDK");System.out.println(content);//要求 验证一个 手机号, 要求必须是以 138 139 开头的content = "13988889999";if (content.matches("13(8|9)\\d{8}")) {System.out.println("验证成功");} else {System.out.println("验证失败");}//要求按照 # 或者 - 或者 ~ 或者 数字 来分割System.out.println("===================");content = "hello#abc-jack12smith~北京";String[] split = content.split("#|-|~|\\d+");for (String s : split) {System.out.println("s = " + s);}}
}

6 正则表达式使用案例

6.1 验证电子邮箱格式是否合法

package regularexpression;/*** @package: regularexpression* @description:验证电子邮件格式是否合法* @author: Yunyang* @date: 2023/12/3  21:31* @version:1.0**/
public class CheckEmail {public static void main(String[] args) {// String content = "hsp@shun.cn.com";String content = "2834660387@qq.com.cn";String regStr = "^[\\w-]+@([a-zA-Z]+\\.)+[a-zA-Z]+$";// String 的matches是整体匹配if(content.matches(regStr)){System.out.println("匹配成功");} else {System.out.println("匹配失败");}}
}

6.2 验证手机号码是否合法

要求: 必须以 13,14,15,18 开头的 11 位数 , 比如 13588889999

package regularexpression;import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** @package: regularexpression* @description:验证手机号码是否合法* @author: Yunyang* @date: 2023/11/26  21:20* @version:1.0**/
public class CheckPhone {public static void main(String[] args) {// 要求: 必须以 13,14,15,18 开头的 11 位数 , 比如 13588889999String content = "13588889999";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("不满足格式");}System.out.println(Pattern.matches(regStr, content));}
}

6.3 验证URL格式是否合法

package regularexpression;import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** @package: regularexpression* @description:正则表达式的应用:url* @author: Yunyang* @date: 2023/11/26  21:42* @version:1.0**/
public class RegExp11 {public static void main(String[] args) {// String content = "https://www.bilibili.com/video/BV1Eq4y1E79W?p=17&spm_id_from=pageDriver";String content = "https://docs.qq.com/doc/DR1NvRkNFU2ZpWGxQ?u=fc936b78ceee42de9e76d148895f84f3";/** 思路:* 1.先确定url的开始部分 http | https://* 2.然后通过([\w-]+\.)+[\w-]+ 匹配www.bilibili.com* 3.3. /video/BV1fh411y7R8?from=sear 匹配(\/[\w-?=&/%.#]*)?** */String regStr = "^((http|https)://)?([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$";//注意:[. ? *]表示匹配就是.本身Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);if(matcher.find()){System.out.println("满足格式");} else {System.out.println("不满足格式");}}
}

7 正则表达式底层实现

package regularexpression;import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** @package: regularexpression* @description:分析Java正则表达式的底层实现* @author: Yunyang* @date: 2023/11/26  17:28* @version:1.0**/
public class RegTheory {public static void main(String[] args) {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平台的标准版),应用于桌面环境;J2EE(Java 2Enterprise Edition,Java 2平台的企业版),应用于基于Java的应用服务器。Java 2平台的发布,是Java发展过程中最重3443要的一个里程碑,标志着Java的应用开始普及9889。";//匹配所有四个数字//1.\\d表示一个数字String regStr = "(\\d\\d)(\\d\\d)";//2.创建正则表达式对象Pattern pattern = Pattern.compile(regStr);//3.创建匹配器Matcher matcher = pattern.matcher(content);//4.开始匹配/**matcher.find()完成的任务 (考虑分组):* 什么是分组,比如 (\d\d)(\d\d) ,正则表达式中有() 表示分组,第 1 个()表示第 1 组,第 2 个()表示第 2 组...*1.根据指定的规则,定位满足规则的子字符串(比如1998)*2.找到后,将 子字符串的开始的索引记录到 matcher 对象的属性 int[] groups;*  2.1 groups[0] = 0 , 把该子字符串的结束的索引+1 的值记录到 groups[1] = 4*  2.2 记录 1 组()匹配到的字符串 groups[2] = 0 groups[3] = 2*  2.3 记录 2 组()匹配到的字符串 groups[4] = 2 groups[5] = 4*  2.4 .如果有更多的分组.....* 3.同时记录 oldLast 的值为 子字符串的结束的 索引+1 的值即 35, 即下次执行 find 时,就从 35 开始匹配***  源码:*  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();*     }从代码中可以看出,数组中的每个分组的信息由两个连续的元素表示:一个是分组的开始位置,另一个是结束位置。因此,对于给定				的 group,它的开始和结束位置分别是 groups[group*2] 和 groups[group*2+1],检查发现开始或结束位置为-1,则返				回 null,表示该分组在匹配的字符串中不存在** 1.根据group[0]=31 和groups[1]=35的记录的位置,从 content 开始截取子字符串返回* 就是 [31,35) 包含 31 但是不包含索引为 35 的位置** 如果再次指向 find 方法.仍然按照上面分析来执行*/while (matcher.find()) {//小结//1. 如果正则表达式有() 即分组//2. 取出匹配的字符串规则如下//3. group(0) 表示匹配到的子字符串//4. group(1) 表示匹配到的子字符串的第一组字串//5. group(2) 表示匹配到的子字符串的第 2 组字串//6. ... 但是分组的数不能越界.System.out.println("找到 " + matcher.group(0));System.out.println("第1组()匹配到的值=" + matcher.group(1));System.out.println("第2组()匹配到的值=" + matcher.group(2));}}
}

8 Reference

  1. 【韩顺平讲Java】Java 正则表达式专题 -正则 正则表达式 元字符 限定符 Pattern Matcher 分组 捕获 反向引用等

  2. 菜鸟教程:Java正则表达式

  3. 《正则表达式必知必会》 作者: [美] Ben Forta 著 , 杨涛 译

  4. 正则表达式在线工具

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com