正则表达式
是什么
正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。
许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成“regex”,单数有regexp、regex,复数有regexps、regexes、regexen。(注:来自百度百科)
为什么
在说为什么之前我先提一个问题,我们在做用户注册的时候经常要填写手机号,电子邮箱等信息,我们肯定需要对这些数据进行校验,那么我们该怎么做?
我一般学习新技术的都是带着问题学习,既然会出现新的技术,肯定是目前的技术处出现了什么问题,还是老三步(是什么[是什么技术,哪个方面的技术,基本概念等等],为什么[为什么会出现这个新技术,以前的技术出现了什么问题,为什么会出现这种问题],怎么做[新技术解决了哪些问题,怎么解决的]),大家如果觉得这种方式不错的话可以尝试一下
在开发过程中需要使用的大量的字符串匹配 工作,比如查找文本功能,比如替换功能,比如网络爬虫爬取到了大量数据,需要在大量数据中进行筛选操作,得到我们想要的数据,还比如验证用户输入内容是否是我们想要的格式
但是往往这些单纯的靠字符串匹配是很难做到的,这时候就该正则表达式闪亮登场了
电子邮箱可以给input
标签设置type="email"
手机号设置type="number"
并不能达到理想的效果js代码实现循环逐位测试效率极低、代码臃肿,这时候我们就可以使用正则表达式进行匹配
怎么用
正则基础语法
基础使用
这是最基本的一种方式之一,直接输入abc
就可以精准匹配到abc
这三个字符.这一般的匹配方式都可以做到,正则的精髓还是在下面这些功能中
元字符
大多数都是以 \
开头的
元字符 | 备注 |
---|---|
\d | 匹配数字 等价于 ==> [0-9] |
\w | 匹配单词字符(英文字符大小写+数字+下划线) 等价于==> [a-zA-Z0-9_] |
\s | 匹配空白符(空白符,包括空格,制表符(Tab),换行符,中文全角空格等) |
\D | 匹配任意非数字的字符 |
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\S | 匹配任意不是空白符的字符 |
\b | 匹配单词边界 |
. (点) | 匹配任意字符,不包括换行符 |
^ | 表示行首 |
$ | 表示行尾 |
转义
刚刚我们已经使用了一些特殊字符,比如 * . + ?
等等,当我们要使用其本身的含义的时候就需要使用转义 ; 像大部分语言一样,转义符使用的是 \
(反斜杠)
我们只需要在需要转义的字符前面加上\即可 如 \? \*
正则中需要转义的特殊字符:
$ | () | * | + |
---|---|---|---|
.(点) | [ | \ | ? |
^ | { | | |
限定符
? | 0次或1次 |
---|---|
* | 0次或多次 |
+ | 1次或多次 |
{n} | 指定次数次,{3} 表示匹配三次 (固定) |
{n,} | 重复n次或更多次, {2,} 表示匹配2次以及更多 |
{n,m} | 重复n到m次, {2,6} 2次到6次之间,包含2和6 |
注:以上都是默认匹配前面一项,如果想匹配前面一部分请使用( )
看下节
分组
我们已经提到了怎么重复单个字符(直接在字符后面加上限定符就行了);但如果想要重复多个字符又该怎么办?你可以用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了,你也可以对子表达式进行其它一些操作
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
举个栗子:
通过\b(\w+)\b\s+\1\b
表达式 就可以匹配 连个重复的单词,例如go go
我们也可以自己指定子表达式的组名。要指定一个子表达式的组名,请使用这样的语法:(?<Word>\w+)
(或者把尖括号换成’也行:(?'Word'\w+)
,这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,你可以使用\k<Word>
,所以上一个例子也可以写成这样:\b(?<Word>\w+)\b\s+\k<Word>\b
。
运算符
|
:或,如(a|b)
匹配a或者b 括号很有必要[***]
匹配到的东西只能是括号内的的,如[abc]
:只能匹配到a或b或c
1). 在[]
内使用 - 表示范围,如[a-z]
匹配从a到z的所有小写字符,[0-8]
表示匹配从0到8之间的所有数字
2). 在[]
内前面添加^
,表示匹配[]
里显示的文本以外的内容,如[^abc]
,表示匹配的是除了a,b,c以外的所有字符
贪婪匹配和与懒惰匹配
贪婪匹配:尽可能匹配多的字符
懒惰匹配:尽可能匹配少的内容
正则: \bhttp://.+/
字符串: http://localhost/api/login
我们想获取这个内容中的主机名"localhost",
使用下面的正则匹配上面的字符串,却发现匹配到的是
"localhost/api"
这是因为正则表达式默认使用贪婪匹配,
我们可以把正则表达式改成下面这个
\bhttp://.+?/
你可以发现我们只是添加了一个 ? ,就切换到了懒惰匹配
经量匹配少的内容
正则中默认使用的是贪婪匹配
在限定符后面添加一个?
即可切换懒惰匹配
断言
一、零宽断言
(?=exp)
零宽度正预测先行断言:它断言自身后面会匹配到exp\b\w+(?=!) #匹配一个单词,单词的后面跟着一个 ! 号 Hello KangKang! I ate fried chicken in People's Square. 匹配到的就是 KangKang
(?<=exp)
零宽度正回顾后发断言:它断言自身前面会匹配exp<div><span>我是内容</span></div> (?<=<span>).*(?=</span>) #匹配<span>到</span>中间的内容 得到"我是内容"
一、反向零宽断言
(?!exp)
匹配后面跟的不是exp的位置
(?<!exp)
匹配前面不是exp的位置
在java中使用 正则表达式
在Java中使用正则表达式,首先得知道两个类,一个叫做Pattern
,一个叫做Matcher
,这两个类都是java.util.regex
包下的,这个包下也就这两个类
Pattern类
Pattern
类是用来干嘛的呢,其实我们可以把他简单理解为就是一个正则表达式(就像File类一样,我们可以简单理解为它就是一个文件)。Pattern类没有公共的构造方法,这意味着我们不能直接new一个Pattern类的对象。在这个类中,提供了一个方法,名字叫compile
,我们将正则表达式作为参数,传入这个方法中,就可以得到一个Pattern对象,我们可以将这个对象理解为就是传入的正则表达式。
Pattern类有一个实例方法,叫做matcher,这个方法接收一个参数,就是需要匹配的字符串,方法的返回值就是一个Mather对象。
Matcher类
Matcher
类又是用来干嘛的呢?Matcher这个单词翻译过来就是匹配器的意思,一个Matcher对象就是一个匹配器,我们通过这个匹配器,就可以操作正则表达式与字符串的匹配过程。操作的是哪个正则表达式和字符串呢?就是我们调用Pettern类的compile方法生成的Pettern对象,以及调用Pettern对象的matcher方法传入的要匹配的字符串。通过这个匹配器对象,我们可以控制字符串的匹配,查看匹配结果,甚至可以替换等便利的操作。
小Demo
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Demo.java
* regex
*
* @author Yuanao
* @date 2021/11/29 13:59
*/
public class Demo {
public static void main(String[] args) {
// 使用Pattern类的compile方法,传入一个正则表达式,得到一个Pattern对象
Pattern pattern = Pattern.compile("[0-9]+");
// 调用pattern对象的matcher方法,传入需要匹配的字符串, 得到一个匹配器对象
Matcher matcher = pattern.matcher("abcd123acca123a1a2");
// 从字符串开头,逐一向后匹配,直到无法再匹配为止
while(matcher.find()) {
// 输出上一次匹配的内容
System.out.print(matcher.group() + ": ");
// 输出上一次匹配的首尾索引
System.out.println(matcher.start() + "->" + (matcher.end()-1) );
}
}
}
附录
正则相关的一些好的连接