正则表达式
正则表达式
什么是正则表达式?
正则表达式,又称规则表达式,英文名为Regular Expression,在代码中常简写为regex、regexp或RE,是计算机科学的一个概念。正则表通常被用来检索、替换那些符合某个模式(规则)的文本。
首先,正则只和字符串有关。在线测试工具 http://tool.chinaz.com/regex/
给定一个正则表达式和另一个字符串,我们可以达到如下的目的:
1. 给定的字符串是否符合正则表达式的过滤逻辑(称作"匹配");
2. 可以通过正则表达式,从字符串中获取我们想要的特定部分。
正则表达式的特点是:
1. 灵活性、逻辑性和功能性非常强;
2. 可以迅速地用极简单的方式达到字符串的复杂控制。
3. 对于刚接触的人来说,比较晦涩难懂。
符号:
元字符 |
描述 |
---|---|
将下一个字符标记符、或一个向后引用、或一个八进制转义符。例如,"\n"匹配n。"n"匹配换行符。序列"\"匹配""而"("则匹配"("。 即相当于多种编程语言中都有的"转义字符"的概念。 |
|
^ |
匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配"n"或"r"之后的位置。 |
$ |
匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配"n"或"r"之前的位置。 |
* |
匹配前面的子表达式任意次。例如,zo*能匹配"z",也能匹配"zo"以及"zoo"。*等价于o{0,} |
+ |
匹配前面的子表达式一次或多次(大于等于1次)。例如,"zo+"能匹配"zo"以及"zoo",但不能匹配"z"。+等价于{1,}。 |
? |
匹配前面的子表达式零次或一次。例如,"do(es)?"可以匹配"do"或"does"中的"do"。?等价于{0,1}。 |
{n} |
n是一个非负整数。匹配确定的n次。例如,"o{2}"不能匹配"Bob"中的"o",但是能匹配"food"中的两个o。 |
{n,} |
n是一个非负整数。至少匹配n次。例如,"o{2,}"不能匹配"Bob"中的"o",但能匹配"foooood"中的所有o。"o{1,}" 等价于"o+"。"o{0,}"则等价于"o*"。 |
{n,m} |
m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,"o{1,3}"将匹配"fooooood"中的前三个o为一组, 后三个o为一组。"o{0,1}"等价于"o?"。请注意在逗号和两个数之间不能有空格。 |
? |
当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串, 而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串"oooo","o+"将尽可能多的匹配"o",得到结果["oooo"], 而"o+?"将尽可能少的匹配"o",得到结果 ['o', 'o', 'o', 'o'] |
.点 |
匹配除"rn"之外的任何单个字符。要匹配包括"rn"在内的任何字符,请使用像"[sS]"的模式。 |
(pattern) |
匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合, 在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用"("或")"。 |
(?:pattern) |
非获取匹配,匹配pattern但不获取匹配结果,不进行存储供以后使用。这在使用或字符"(|)"来组合一个模式的各个部分时很有用。 例如"industr(?:y|ies)"就是一个比"industry|industries"更简略的表达式。 |
(?=pattern) |
非获取匹配,正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。 例如,"Windows(?=95|98|NT|2000)"能匹配"Windows2000"中的"Windows",但不能匹配"Windows3.1"中的"Windows"。 预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) |
非获取匹配,正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。 例如"Windows(?!95|98|NT|2000)"能匹配"Windows3.1"中的"Windows",但不能匹配"Windows2000"中的"Windows"。 |
(?<=pattern) |
非获取匹配,反向肯定预查,与正向肯定预查类似,只是方向相反。例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中 的"Windows",但不能匹配"3.1Windows"中的"Windows"。 |
(?<!pattern) |
非获取匹配,反向否定预查,与正向否定预查类似,只是方向相反。例如"(?<!95|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows", 但不能匹配"2000Windows"中的"Windows"。这个地方不正确,有问题此处用或任意一项都不能超过2位,如"(?<!95|98|NT|20)Windows正确, "(?<!95|980|NT|20)Windows 报错,若是单独使用则无限制,如(?<!2000)Windows 正确匹配 |
x|y |
匹配x或y。例如,"z|food"能匹配"z"或"food"(此处请谨慎)。"[zf]ood"则匹配"zood"或"food"。 |
[xyz] |
字符集合。匹配所包含的任意一个字符。例如,"[abc]"可以匹配"plain"中的"a"。 |
[^xyz] |
负值字符集合。匹配未包含的任意字符。例如,"[^abc]"可以匹配"plain"中的"plin"。 |
[a-z] |
字符范围。匹配指定范围内的任意字符。例如,"[a-z]"可以匹配"a"到"z"范围内的任意小写字母字符。 注意:只有连字符在字符组内部时,并且出现在两个字符之间时,才能表示字符的范围; 如果出字符组的开头,则只能表示连字符本身. |
[^a-z] |
负值字符范围。匹配任何不在指定范围内的任意字符。例如,"[^a-z]"可以匹配任何不在"a"到"z"范围内的任意字符。 |
b |
匹配一个单词边界,也就是指单词和空格间的位置(即正则表达式的"匹配"有两种概念,一种是匹配字符,一种是匹配位置, 这里的b就是匹配位置的)。例如,"erb"可以匹配"never"中的"er",但不能匹配"verb"中的"er"。 |
B |
匹配非单词边界。"erB"能匹配"verb"中的"er",但不能匹配"never"中的"er"。 |
cx |
匹配由x指明的控制字符。例如,cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的"c"字符。 |
d |
匹配一个数字字符。等价于[0-9]。grep 要加上-P,perl正则支持 |
D |
匹配一个非数字字符。等价于[^0-9]。grep要加上-P,perl正则支持 |
f |
匹配一个换页符。等价于x0c和cL。 |
n |
匹配一个换行符。等价于x0a和cJ。 |
r |
匹配一个回车符。等价于x0d和cM。 |
s |
匹配任何不可见字符,包括空格、制表符、换页符等等。等价于[ fnrtv]。 |
S |
匹配任何可见字符。等价于[^ fnrtv]。 |
t |
匹配一个制表符。等价于x09和cI。 |
v |
匹配一个垂直制表符。等价于x0b和cK。 |
w |
匹配包括下划线的任何单词字符。类似但不等价于"[A-Za-z0-9_]",这里的"单词"字符使用Unicode字符集。 |
W |
匹配任何非单词字符。等价于"[^A-Za-z0-9_]"。 |
xn |
匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,"x41"匹配"A"。"x041"则等价于"x04&1"。 正则表达式中可以使用ASCII编码。 |
num |
匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,"(.)1"匹配两个连续的相同字符。 |
n |
标识一个八进制转义值或一个向后引用。如果n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7), 则n为一个八进制转义值。 |
nm |
标识一个八进制转义值或一个向后引用。如果nm之前至少有nm个获得子表达式,则nm为向后引用。如果nm之前至少有n个获取, 则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若n和m均为八进制数字(0-7),则nm将匹配八进制转义值nm。 |
nml |
如果n为八进制数字(0-7),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。 |
un |
匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,u00A9匹配版权符号(©)。 |
p{P} |
小写 p 是 property 的意思,表示 Unicode 属性,用于 Unicode 正表达式的前缀。中括号内的"P"表示Unicode 字符集七个字符属性之一:标点字符。 其他六个属性: L:字母; M:标记符号(一般不会单独出现); Z:分隔符(比如空格、换行等); S:符号(比如数学符号、货币符号等); N:数字(比如阿拉伯数字、罗马数字等); C:其他字符。 *注:此语法部分语言不支持,例:javascript。 |
< > |
匹配词(word)的开始(<)和结束(>)。例如正则表达式<the>能够匹配字符串"for the wise"中的"the",但是不能匹配 字符串"otherwise"中的"the"。注意:这个元字符不是所有的软件都支持的。 |
( ) |
将( 和 ) 之间的表达式定义为"组"(group),并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存9个), 它们可以用 1 到9 的符号来引用。 |
| |
将两个匹配条件进行逻辑"或"(Or)运算。例如正则表达式(him|her) 匹配"it belongs to him"和"it belongs to her",但是不能 匹配"it belongs to them."。注意:这个元字符不是所有的软件都支持的。 |
注:上面摘自《正则表达式之道》
对于符号的简单分析:
字符组 : [字符组] 在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[]表示 字符分为很多类,比如数字、字母、标点等等。 假如你现在要求一个位置"只能出现一个数字",那么这个位置上的字符只能是0、1、2...9这10个数之一。
正则 |
待匹配字符 |
匹配 结果 |
说明 |
---|---|---|---|
[0123456789] |
8 |
True |
在一个字符组里枚举合法的所有字符,字符组里的任意一个字符 和"待匹配字符"相同都视为可以匹配 |
[0123456789] |
a |
False |
由于字符组中没有"a"字符,所以不能匹配 |
[0-9] |
7 |
True |
也可以用-表示范围,[0-9]就和[0123456789]是一个意思 |
[a-z] |
s |
True |
同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示 |
[A-Z] |
B |
True |
[A-Z]就表示所有的大写字母 |
[0-9a-fA-F] |
e |
True |
可以匹配数字,大小写形式的a~f,用来验证十六进制字符 |
字符:
元字符 |
匹配内容 |
---|---|
. |
匹配除换行符以外的任意字符 |
w |
匹配字母或数字或下划线 |
s |
匹配任意的空白符 |
d |
匹配数字 |
n |
匹配一个换行符 |
t |
匹配一个制表符 |
b |
匹配一个单词的结尾 |
^ |
匹配字符串的开始 |
$ |
匹配字符串的结尾 |
W |
匹配非字母或数字或下划线 |
D |
匹配非数字 |
S |
匹配非空白符 |
a|b |
匹配字符a或字符b |
() |
匹配括号内的表达式,也表示一个组 |
[...] |
匹配字符组中的字符 |
[^...] |
匹配除了字符组中字符的所有字符 |
量词:
量词 |
用法说明 |
---|---|
* |
重复零次或更多次 |
+ |
重复一次或更多次 |
? |
重复零次或一次 |
{n} |
重复n次 |
{n,} |
重复n次或更多次 |
{n,m} |
重复n到m次 |
. ^ $
正则 |
待匹配字符 |
匹配 结果 |
说明 |
---|---|---|---|
海. |
海燕海娇海东 |
海燕海娇海东 |
匹配所有"海."的字符 |
^海. |
海燕海娇海东 |
海燕 |
只从开头匹配"海." |
海.$ |
海燕海娇海东 |
海东 |
只匹配结尾的"海.$" |
*+?{}
正则 |
待匹配字符 |
匹配 结果 |
说明 |
---|---|---|---|
李.? |
李杰和李莲英和李二棍子 |
李杰 李莲 李二 |
?表示重复零次或一次,即只匹配"李"后面一个任意字符 |
李.* |
李杰和李莲英和李二棍子 |
李杰和李莲英和李二棍子 |
*表示重复零次或多次,即匹配"李"后面0或多个任意字符 |
李.+ |
李杰和李莲英和李二棍子 |
李杰和李莲英和李二棍子 |
+表示重复一次或多次,即只匹配"李"后面1个或多个任意字符 |
李.{1,2} |
李杰和李莲英和李二棍子 |
李杰和 李莲英 李二棍 |
{1,2}匹配1到2次任意字符 |
注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
正则 |
待匹配字符 |
匹配 结果 |
说明 |
---|---|---|---|
李.*? |
李杰和李莲英和李二棍子 |
李 李 李 |
惰性匹配 |
字符集 [ ] [^ ]
正则 |
待匹配字符 |
匹配 结果 |
说明 |
---|---|---|---|
李[杰莲英二棍子]* |
李杰和李莲英和李二棍子 |
李杰 李莲英 李二棍子 |
表示匹配"李"字后面[杰莲英二棍子]的字符任意次 |
李[^和]* |
李杰和李莲英和李二棍子 |
李杰 李莲英 李二棍子 |
表示匹配一个不是"和"的字符任意次 |
[d] |
456bdha3 |
4 5 6 3 |
表示匹配任意一个数字,匹配到4个结果 |
[d]+ |
456bdha3 |
456 3 |
表示匹配任意个数字,匹配到2个结果 |
分组 ( ) | [ ^ ]
身份证号码是一个长度为15或18个字符的字符串,如果是15位则全部?️数字组成,首位不能为0;如果是18位,则前17位全部是数字,末位可能是数字或x,下面我们尝试用正则来表示:
正则 |
待匹配字符 |
匹配 结果 |
说明 |
---|---|---|---|
^[1-9]d{13,16}[0-9x]$ |
110101198001017032 |
110101198001017032 |
表示可以匹配一个正确的身份证号 |
^[1-9]d{13,16}[0-9x]$ |
1101011980010170 |
1101011980010170 |
表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个16位的数字 |
^[1-9]d{14}(d{2}[0-9x])?$ |
1101011980010170 |
False |
现在不会匹配错误的身份证号了 ()表示分组,将d{2}[0-9x]分成一组,就可以整体约束他们出现的次数为0-1次 |
^([1-9]d{16}[0-9x]|[1-9]d{14})$ |
110105199812067023 |
110105199812067023 |
表示先匹配[1-9]d{16}[0-9x]如果没有匹配上就匹配[1-9]d{14} |
转义符
在正则表达式中,有很多有特殊意义的是元字符,比如d和s等,如果要在正则中匹配正常的"d"而不是"数字"就需要对""进行转义,变成'\'。
在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中也有特殊的含义,本身还需要转义。所以如果匹配一次"d",字符串中要写成'\d',那么正则里就要写成"\\d",这样就太麻烦了。这个时候我们就用到了r'd'这个概念,此时的正则是r'\d'就可以了。
正则 |
待匹配字符 |
匹配 结果 |
说明 |
---|---|---|---|
d |
d |
False |
因为在正则表达式中是有特殊意义的字符,所以要匹配d本身,用表达式d无法匹配 |
\d |
d |
True |
转义之后变成\,即可匹配 |
"\\d" |
'\d' |
True |
如果在python中,字符串中的''也需要转义,所以每一个字符串''又需要转义一次 |
r'\d' |
r'd' |
True |
在字符串之前加r,让整个字符串不转义 |
贪婪匹配
贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
正则 |
待匹配字符 |
匹配 结果 |
说明 |
---|---|---|---|
<.*> |
<script>...<script> |
<script>...<script> |
默认为贪婪匹配模式,会匹配尽量长的字符串 |
<.*?> |
<script>...<script> |
<script> <script> |
加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串 |
几个常用的非贪婪匹配Pattern
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
.*?的用法
. 是任意字符
* 是取 0 至 无限长度
? 是非贪婪模式。
何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:
.*?x
就是取前面任意长度的字符,直到一个x出现
- TSQL--临时表和表变量
- 微软开源 C++ REST SDK
- 使用Autofac在ASP.NET Web API上实现依赖注入
- Universal-Image-Loader完全解析--从源代码分析Universal-Image-Loader中的线程池
- 我是怎样爬下6万共享单车数据并进行分析的(附代码)
- 数据库压缩备份提高备份效率
- 教你用TensorFlow和自编码器模型生成手写数字(附代码)
- 开源OCR引擎Tesseract
- 数据仓库中如何使用索引
- PowerBI 引入时间智能
- 列存储索引1:初识列存储索引
- 通过案例来学习TCP的MSS、MTU
- webview和js交互
- 比较列存储索引与行索引
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 树莓派基础实验17:温度传感器实验
- Java Servlet详解(体系结构+注解配置+生命周期)
- RabbitMq如何确保消息不丢失
- 《sql必知必会》——读书笔记(4)
- AkShare-债券数据-国债期货可交割券相关指标
- Linux From Scratch
- 介绍一款 API 敏捷开发工具
- java线程池(五):ForkJoinPool源码分析之一(外部提交及worker执行过程)
- JavaScript中的匿名函数、闭包和BOM
- 【Vue.js】Vue.js中的事件处理、过滤器、过渡和动画、组件的生命周期及组件之间的通信
- 树莓派基础实验18:声音传感器实验
- 树莓派基础实验19:光敏传感器实验
- 逻辑式编程还有用吗?--“三维度”逻辑编程语言的设计(2)
- git 报错解决Validate branches Cannot Create: This merge request already exists
- 树莓派基础实验20:火焰报警传感器实验