正则表达式(Regex)基础语法

正则表达式(也称为 Regex)是用于匹配文本中模式的强大工具。它们广泛应用于文本处理、数据验证和搜索操作。比如需要处理字符串以验证用户输入的数据、验证 URL 格式、替换段落中的单词等。几乎所有主要的编程语言都支持正则表达式。正则表达式有以下主要用途:

在大量文本中搜索特定项目。 例如,你可能希望在某些内容中使用文本编辑器识别出所有的电子邮件地址。

替换特定项目。 例如,你可能希望通过文本编辑器将一些格式不佳的 HTML 中的所有大写标签替换为小写等效标签。

验证输入。 例如,你可能希望检查一个密码是否符合某些条件,如包含大写和小写字母、数字、标点符号等,用于你正在编写的程序中。

协调操作。 例如,你可能希望处理某个目录中的某些文件,但只在它们符合特定条件时才进行处理,这通常在命令行中进行。

重新格式化文本。 例如,你可能将数据从一个程序导出为文本文件,然后通过文本编辑器修改其布局,以便将其导入另一个程序中。

什么是正则表达式

正则表达式(Regular Expression简写为Regex),又称为规则表达式,它是一种强大的文本匹配模式,其用于在字符串中查找匹配符合特定规则的子串。

正则表达式是独立于编程语言而存在的,它并不依赖于某种编程语言。只要一种编程语言实现了正则表达式引擎,那么这种编程语言,就具备了正则表达式模式匹配的功能。每种工具或编程语言对正则表达式的实现,虽有细节上的不同,但基本的使用是相同的。

正则表达式可以用于执行各种文本搜索和文本替换操作。正则表达式让你能够轻松进行复杂的文本搜索和操作。它们具有高度的灵活性,可用于广泛的任务,从简单搜索到高级文本处理。

正则表达式的基本工作原理如下:

正则表达式的基本语法

正则表达式由一些普通字符(比如英文字母,文本信息,数字)和元字符(具有特定含义的字符)组成。

正则表达式作为一个字符模板,在字符串中匹配一个或多个符合特定规则的子串。

  • 元字符(Metacharacters)
    元字符(Metacharacters)是在正则表达式中具有特殊含义的字符。

.: 匹配除换行符之外的任何字符。

^: 用于匹配字符串的开始位置,或者在中括号内使用时表示对字符集的否定(即取反)。

$: 匹配字符串的结束。

*: (量词)匹配前面元素的0次或多次重复。

+: (量词)匹配前面元素的1次或多次重复。

?: (量词)匹配前面元素的0次或1次重复。

{}: (量词)大括号用于匹配次数。

\]: 匹配括号内的任何单个字符。 ():括号用于将正则表达式的部分进行分组。 :反斜杠还可以用来引入一些特殊的字符序列,这些序列在正则表达式中具有特定的含义;转义特殊字符。 * **预定义的字符类(Character Classes)** 字符类匹配一组字符中的任何一个。 \\d :匹配任何数字。等价于 \[0-9\]。 \\D :匹配任何非数字字符。等价于 \[\^0-9\]。 \\w :匹配任何字母数字字符或下划线。等价于 \[a-zA-Z0-9_\]。 \\W :匹配任何非字母数字字符。等价于 \[\^a-zA-Z0-9_\]。 \\s :匹配任何空白字符。 \\S :匹配任何非空白字符。 * **限定符,又称为 量词(Quantifier)** 限定符也属于元字符,用来限定一个子表达式出现的次数。 量词(Quantifier)定义了文本信息中一个子表达式必须出现的次数。 量词(Quantifier),限定符: \*:匹配前面的元素0次或多次。 +:匹配前面的元素1次或多次。 ?: 匹配前面的元素0次或1次。 {n}: 匹配前面的元素恰好n次。 {n,}: 匹配前面的元素至少 n 次(n次或更多次)。 {n,m}: 匹配前面的元素n次到m次(至少 n 次,但是不超过 m 次)。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/62e23fa85bf54e6bb39bd4511d545afa.jpeg) * **特殊字符** 使用特殊字符可以编写更高级的模式表达式,常见的特殊字符如下: ​​.​​:匹配除了换行符之外的任何单个字符。 ​​\\​​:将下一个字符标记为特殊字符、或原义字符、或向后引用、或八进制转义符。 ​​\|​​:逻辑或操作符。 ​​\[\^\]​​:取非,匹配未包含的任意字符。 - :此符号写在中括号\[\],表示范围。 **逻辑符号:逻辑或 \|** 符号 \| 写在两个子表达式之间,表示两个子表达式是逻辑或的关系。 例如:模式串ab\|cd,表示匹配ab 或 cd。 **符号 - 写在中括号\[\],表示范围的意思** ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/002741deaf9841cd9b6446bf88ca20c9.jpeg) 常见的使用范围的方式如下: 部分范围:​​\[a-f\]​​,匹配 a 到 f 的任意字符。 小写范围:​​\[a-z\]​​,匹配 a 到 z 的任意字符。 大写范围:​​\[A-Z\]​​,匹配 A 到 Z 的任意字符。 数字范围:​​\[0-9\]​​,匹配 0 到 9 的任意字符。 符号范围:​​\[#$%\&@\]​​。 混合范围:​​\[a-zA-Z0-9\]​​,匹配所有数字、大小写字母中的任意字符。 **示例** 如果想要写一个匹配三个字母的单词的Regex表达式,怎么写呢?根据上面的规则,可以这样来写: ```cpp [a-z][a-z][a-z] //匹配三个字母的单词的Regex表达式 ``` 这里我们匹配的是三个字母的单词,那如果想要匹配5个、20个、n个字母的单词呢?难道要重复n次吗?有一种更好的方法就是使用 \*\*花括号​​{} \*\*​​ 来表示,来看例子: ```cpp [a-z]{5} //匹配5个字母的单词的Regex表达式 [a-z]{n} //匹配n个字母的单词的Regex表达式 ``` 其实匹配重复字符的更灵活的语法是这样的:​​{m,n}​​,它会匹配前面一个字符至少 m 次至多 n 次重复,{m}表示匹配 m 次,{m,}表示至少 m 次。 除了可以使用 \*\*花括号​​{} \*\*​​ 来匹配一定数量的字符,还有三个相关的模式: ​​+​​​:匹配前面一个表达式一次或者多次,相当于​​{1,}​​。 ​​\*​​​:匹配前面一个表达式0次或者多次,相当于​​{0,}​​。 ​​?​​​:单独使用匹配前面一个表达式零次或者一次,相当于​​{0,1}​​,如果跟在量词 \*、+、?、{}后面的时候将会使量词变为非贪婪模式(尽量匹配少的字符),默认是使用贪婪模式。 * **锚点(Anchors),又称为边界匹配器** 锚点用于匹配字符串中的位置。例如:开始位置\^与结束位置$ 符号\^ 表示匹配的子串在文本信息的行首,符号$ 表示匹配的子串在文本信息的行尾。 \^: 表示文本行的开头。符号用于匹配字符串的开始位置。 $ :表示文本行的结尾。符号(尽管在你的列表中未直接给出,但它是常用的表示字符串结束的锚点)用于匹配字符串的结束位置。 \\b :用于匹配单词边界,即单词字符(如字母、数字或下划线)与非单词字符(如空格、标点符号等)之间的位置。 \\B :匹配非单词边界,即两个单词字符之间或两个非单词字符之间的位置。 * **子表达、组(Groups )和前瞻后顾(Lookarounds)** 组(Groups )和前瞻后顾(Lookarounds)用于捕获模式中的部分内容并执行高级匹配。 组(Groups):在正则表达式中,组允许你将模式的一部分用 **圆括号()** 括起来作为一个独立的单元,通常称为子表达。这样不仅更容易地引用或操作匹配到的那部分文本,还可以在更复杂的表达式中重复使用该模式。在大多数正则表达式引擎中,都可以用 **圆括号()** 括起来定义子表达。 前瞻后顾(Lookarounds):前瞻和后顾是两种特殊的零宽度断言,它们用于指定一个模式必须出现或不出现的条件,但不消耗(即不匹配)任何字符。前瞻(Lookaheads)用于指定某个模式必须紧跟在当前位置之后,而后顾(Lookbehinds)则用于指定某个模式必须位于当前位置之前。前瞻后顾不会改变正则表达式的匹配位置,只是根据指定的条件来判断是否进行匹配。前瞻和后顾分别包括正前瞻(Positive Lookahead)、负前瞻(Negative Lookahead)、正后顾(Positive Lookbehind)和负后顾(Negative Lookbehind)。 * **贪婪模式(Greedy )、懒惰模式(Lazy )** 正则表达式中贪婪的意思就是贪多,意思就是正则在匹配的过程中,总是去匹配尽可能多的字符,**符号?** 则可以将贪婪转换为非贪婪。 贪婪模式(Greedy ):正则表达式会尽可能多地匹配字符。使用 **正则表达式a.\*b**来匹配字符串axxxbxxxab时,贪婪模式会匹配从第一个a到最后一个b的整个部分axxxbxxxab,因为这样可以确保整个表达式匹配成功,并且匹配了最长的可能字符串。 懒惰模式(Lazy ):正则表达式会尽可能少地匹配字符。同样使用**正则表达式a.\*?b**来匹配字符串axxxbxxxab时,非贪婪模式会匹配从第一个a开始直到第一个b结束的部分axxxb,因为这样可以确保在满足整个表达式匹配成功的前提下,匹配了最短的字符串。 **元字符 ​​? ​​​** :单独使用时匹配前面一个表达式零次或者一次,相当于​​{0,1}​​,例如:a.?b。但是,如果跟在量词 *、+、?、{n}、{n,}、{n,m} 后面的时候,将会使被量词修饰的子表达式变为非贪婪的懒惰模式(尽量匹配少的字符),默认是使用的是贪婪模式。例如,a.*?b会匹配字符串中a和b之间的最短可能字符串,而a.\*b则会匹配最长的可能字符串。 * **转义字符(Escape character)** 转义字符用来对一些元字符进行转义,使这些元字符失去其特定的含义,只表示一个普通的字符。例如,为了 匹配 +、\\、\*、? 等特殊的元字符,必须使用转义字符(\\)来转义。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f6fa3ccb5cfc4320afefd1bab96db9c4.jpeg) 正则表达式(regex)是一种强大的工具,用于在文本中匹配和操作模式,广泛应用于文本处理、数据验证和搜索等场景。理解元字符、量词、字符类、锚点、组和前瞻后顾等基本概念,能够进行复杂的文本搜索、替换和格式化操作。正则表达式的灵活性和多样性使其成为解决文本处理问题的得力工具。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/1d1b675f9ac94a0d95c99b83318a2532.jpeg) String类中用到正则表达式(Regex)的方法: String类的匹配判断功能public boolean matches(String regex) String类的分割功能 public String\[\] split(String regex) String类的替换功能 public String replaceAll(String regex,String replacement) String类的判断功能public boolean matches(String regex)方法,实际上是由后文介绍的Pattern类的matches()实现的。 ```cpp /*** String类中定义的matches(String regex)方法源代码 ***/ public boolean matches(String regex) { return Pattern.matches(regex, this); } ``` 来看一个使用String类的匹配判断功能matches(String regex)的示例一: ```cpp String str = "Hello Java"; String prefix = "heLlo"; System.out.println("----使用简洁的正则表达式进行比较----"); System.out.println("----比较匹配结果:"); System.out.println( str.matches("(?i)" + Pattern.quote(prefix) + ".*")); ``` 顺便说明一下,String类测试两个字符串区域是否相等的regionMatches() 方法,它有两个重载形式: ```cpp /***两个重载形式***/ public boolean regionMatches(int toffset, String other, int ooffset, int len) public boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) ``` 需要说明的是,regionMatches() 方法中的参数String other 是一个字符串,如果传入正则表达式它就无法正确处理了。下面是一个验证示例,给它传入一个正则表达式,无法正确处理。 ```cpp /***用RegionMatches比较:测试两个字符串区域是否相等。***/ public static void strRegionMatches() { //(String str,String prefix) String str = "256"; String prefix = "\\d+"; //传入一个正则表达式,无法正确处理。 //第一个参数用true表示忽略字母大小写 boolean reslut = str.regionMatches(true, 0, prefix, 0, prefix.length()); if (reslut) { System.out.println("用RegionMatches比较结果:"+reslut +" 匹配成功。"); System.out.println("字符串:"+str+"\t匹配串:"+prefix); } else { System.out.println("用RegionMatches比较结果:"+reslut +" 匹配不成功。"); } } ``` **Java中的正则表达式处理相关类Pattern类和Matcher类** Java正则表达式通过java.util.regex包下的Pattern类与Matcher类实现。 Pattern类用于创建一个正则表达式,也可以说创建一个匹配模式,它的构造方法是私有的,不可以直接创建,但可以通过Pattern.complie(String regex)简单工厂方法创建一个正则表达式。 * **Pattern.split(CharSequence input)** Pattern有一个split(CharSequence input)方法,用于分隔字符串,并返回一个String\[\]。 String.split(String regex)很有可能是通过Pattern.split(CharSequence input)来实现的。 * **Pattern.matches(String regex,CharSequence input)是一个静态方法** ,用于快速匹配字符串,该方法适合用于只匹配一次,且匹配全部字符串。 Pattern.matches(String regex,CharSequence input),它与下面这段代码等价 Pattern.compile(regex).matcher(input).matches() * **Pattern.matcher(CharSequence input)** 终于轮到Matcher类登场了,Pattern.matcher(CharSequence input)返回一个Matcher对象。 Matcher类的构造方法是包内可见的(friendly),不能随意创建,只能通过Pattern.matcher(CharSequence input)方法得到该类的实例。Pattern类只能做一些简单的匹配操作。 要想得到更强更便捷的正则匹配操作,那就需要将Pattern与Matcher一起合作。Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持。 **Matcher类提供三个匹配操作方法:** Matcher类提供的这三个匹配操作方法,三个方法均返回boolean类型,当匹配到时返回true,没匹配到则返回false。 * Matcher.matches() matches()对整个字符串进行匹配,只有整个字符串都匹配了才返回true。 * Matcher.lookingAt() lookingAt()对前面的字符串进行匹配,只有匹配到的字符串在最前面才返回true。 * Matcher.find() find()对字符串进行匹配,匹配的字符串可以位于任何位置。 代码示例之一: ```cpp Pattern p=Pattern.compile("\\d+"); Matcher m=p.matcher("128x23"); System.out.println("匹配结果:" + m.matches());//返回false,因为x不能被\d+匹配,导致整个字符串匹配未成功。 m =p.matcher("256"); System.out.println("匹配结果:" + m.matches());//返回true,因为\d+匹配到了整个字符串 ``` 代码示例之二: ```cpp Pattern p=Pattern.compile("\\d+"); Matcher m = p.matcher("128x23"); System.out.println("匹配结果:" + m.lookingAt());//返回true,因为\d+匹配到了前面的128 m =p.matcher("g128x23"); System.out.println("匹配结果:" + m.lookingAt());//返回false,因为\d+不能匹配前面的g ``` 代码示例之三: ```cpp Pattern p=Pattern.compile("\\d+"); Matcher m = p.matcher("128x23"); System.out.println("匹配结果:" + m.find()); //返回true m = p.matcher("g128x23"); System.out.println("匹配结果:" + m.find()); //返回true m = p.matcher("gAxyz"); System.out.println("匹配结果:" + m.find()); //返回false ``` **Matcher类还提供了三个获取匹配信息的方法:start()、end()和group()** 当使用matches() , lookingAt() , find()执行匹配操作后,就可以利用以上三个方法得到更详细的信息: 1,start()方法 返回匹配到的子字符串在字符串中的索引位置。 2,end()方法 返回匹配到的子字符串的最后一个字符在字符串中的索引位置。 3,group()方法 返回匹配到的子字符串。 方法start() , end() , group()均有一个重载方法,它们是start(int i) , end(int i) , group(int i)专用于分组操作,Mathcer类还有一个groupCount()用于返回有多少组。 **捕获组的概念** 捕获组可以通过从左到右计算其开括号来编号,编号是从1 开始的。例如,在表达式 ((A)(B(D))中,存在四个这样的组: 1 ((A)(B(D))) 2 (A) 3 (B(D)) 4 (D) 组零始终代表整个表达式。 以 (?) 开头的组是纯的非捕获组,它不捕获文本,也不针对组合计进行计数。 ```cpp /***捕获组用来提取子字符串。***/ public static void regexGroup() { String text = "My email is [email protected]"; String regex = "(\\w+)@(\\w+\\.\\w+)"; //定义邮箱的规则 Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(text); if (matcher.find()) { System.out.println("完全匹配: " + matcher.group(0)); System.out.println("用户名: " + matcher.group(1)); System.out.println("eMail域名: " + matcher.group(2)); } } ``` 捕获组测试结果如下: 完全匹配: [email protected] 用户名: example eMail域名: 163.com 与组关联的捕获输入始终是与组最近匹配的子序列。如果由于量化的缘故再次计算了组,则在第二次计算失败时将保留其以前捕获的值(如果有的话)例如,将字符串"aba" 与表达式(a(b)?)+ 相匹配,会将第二组设置为 "b"。在每个匹配的开头,所有捕获的输入都会被丢弃。 **参考文献:** [一篇带给你正则表达式完整指南](https://www.51cto.com/article/710479.html) [正则表达式的基本介绍与正则大全](https://cloud.tencent.com/developer/article/2427152) [Java matches类,Pattern类及matcher类用法示例](https://www.jb51.net/article/158300.htm) [详解Java正则表达式中Pattern类和Matcher类](https://www.jb51.net/article/100673.htm) [Regex 正则表达式入门](https://www.jianshu.com/p/6ab09193703c) [关于正则表达式及pcre的介绍](https://zhuanlan.zhihu.com/p/693882819) [Java Regex正则表达式 详解](https://zhuanlan.zhihu.com/p/714423746) [正则表达式](https://blog.csdn.net/jessica_ff/article/details/137729208) [【JavaSE专栏20】浅谈Java中的正则表达式的应用场景](https://zwz99.blog.csdn.net/article/details/131501913) [Java中的正则表达式:从基础到高级应用](https://blog.csdn.net/wangdashu1994/article/details/139846802?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1-139846802-blog-131501913.235%5Ev43%5Epc_blog_bottom_relevance_base9&spm=1001.2101.3001.4242.2&utm_relevant_index=4) [Java正则表达式详解](https://blog.csdn.net/weixin_53622554/article/details/129319177?spm=1001.2101.3001.6650.10&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-10-129319177-blog-131501913.235%5Ev43%5Epc_blog_bottom_relevance_base9&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-10-129319177-blog-131501913.235%5Ev43%5Epc_blog_bottom_relevance_base9&utm_relevant_index=20) [Java中正则表达式的使用](https://blog.csdn.net/qq_56056920/article/details/127920743?spm=1001.2101.3001.6650.12&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-12-127920743-blog-131501913.235%5Ev43%5Epc_blog_bottom_relevance_base9&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-12-127920743-blog-131501913.235%5Ev43%5Epc_blog_bottom_relevance_base9&utm_relevant_index=22) [【JavaSE专栏61】封装,面向对象编程的三大特性之一](https://zwz99.blog.csdn.net/article/details/132014924) [【JavaSE专栏62】继承,JAVA面向对象编程中的一项重要特性](https://zwz99.blog.csdn.net/article/details/132034465) [【JavaSE专栏63】多态,父类引用子类的对象,面向对象编程中的重要概念](https://zwz99.blog.csdn.net/article/details/132048421) [Python录制屏幕,原图无压缩、无水印](https://blog.csdn.net/weixin_41312919/article/details/115088426?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-115088426-blog-108279543.235%5Ev43%5Epc_blog_bottom_relevance_base9&spm=1001.2101.3001.4242.1&utm_relevant_index=3) [Python录制屏幕和摄像头视频用代码亲测可用](https://blog.csdn.net/phker/article/details/108279543) [一文带您了解正则表达式(RegEx):python 示例](https://zhuanlan.zhihu.com/p/721323054)

相关推荐
yychen_java26 分钟前
R-tree详解
java·算法·r-tree
JANYI20181 小时前
嵌入式设计模式基础--C语言的继承封装与多态
java·c语言·设计模式
xrkhy1 小时前
反射, 注解, 动态代理
java
Ten peaches1 小时前
Selenium-Java版(操作元素)
java·selenium·测试工具·html
lyw2056192 小时前
RabbitMQ,Kafka八股(自用笔记)
java
邹诗钰-电子信息工程2 小时前
嵌入式自学第二十一天(5.14)
java·开发语言·算法
有梦想的攻城狮2 小时前
spring中的@MapperScan注解详解
java·后端·spring·mapperscan
寒小松2 小时前
Problem E: List练习
java·数据结构·list
zimoyin2 小时前
Kotlin 协程实战:实现异步值加载委托,对值进行异步懒初始化
java·前端·kotlin
柚个朵朵3 小时前
Spring的Validation,这是一套基于注解的权限校验框架
java·后端·spring