正则表达式
正则表达式
正则表达式是一些用来匹配和处理文本的字符串。
正则表达式是你所定义的模式模板(pattern template )
正则表达式是通过正则表达式引擎是现实的,正则表达式引擎是一套底层软件,负责解释正则表达式模式并使用这些模式进行匹配
Linux
这里以Linux为例,介绍正则表达式
在Linux中,有两种流行的正则表达式引擎,大多数Linux工具至少实现了BRE引擎规范,能够识别该规范定义的所有模式符号,但是sed只符合BRE引擎规范的子集。
- POSIX基础正则表达式(basic regular expression)BRE,
- POSIX扩展正则表达式(extended regular expression)ERE,为常见的模式提供了更高级的使用,如gawk
在linux中可以看到使用awk和gawk的作用是一样的,因为awk是链接到gawk的,gawk是awk的GPL版
gawk程序可以使用大多数扩展正则表达式模式符号,并且能提供一些额外过滤功能,而这些功能是sed不具备的,正因为如此,gawk程序在处理数据流是比较慢。
使用场景
- 搜索 匹配文本
- 替换 匹配并替换
注意点
1.正则表达式使用字符串来匹配,匹配到的未必总是整个字符串,也可能是子串。如果需要匹配整个字符,需要用空格将开头或结尾隔开,或者指明行首行尾。
默认设置
1.绝大多数正则表达式引擎默认只返回一个匹配结果
2.区分大小写
匹配纯文本
/文本内容/
echo "thisis isis a test" | awk '/this/{print $0}'
thisis isis a test
echo "thisis isis a test" | sed -n '/this/p'
thisis isis a test
特殊字符
元字符时一些在正则表达式里有特殊含义的字符,如果需要匹配它们本身,需要在前面加斜杠表示转义,比如匹配 * \*
.*[]^${}\+?|()
元字符大致可以分为两类
- 匹配文本的,比如
.
- 正则表达式语法的组成部分,比如
[和]
特殊字符 | 描述 | 说明 |
---|---|---|
. | 匹配除了\n之外的任意单个字符 | BRE、ERE |
[] | 必须匹配[]其中的某个字符 | BRE 、ERE |
A|B | 或操作 A或者B |
[] 匹配多个字符中的某一个
字符|描述
-|-|-
[] |必须匹配[]其中的某个字符
[-] | 表示字符区间(集合),如大写字母[A-Z]
[^] | 取反操作,不匹配[]中的某字符
适用于从全局看需要区分字母大小写,某个局部不需要区分字母大小写。
[]中字符的关系是or
如匹配子串含有RegEx和regex :[Rr]eg[Ee]x
XregEx也会被匹配,原因是默认匹配的不一定是整个字符串,可以是子串,如果需要匹配整个字符串需要限定位置
案例
test文件
sales.txt
order3.txt
na1.xls
na2.xls
sa1.xls
cal.xls
sam.xls
usal.xls
[ns]a..xls
a前面要有n或者s字符,
a后面需要跟一个任意字符
.xls 任意字符的后面要跟着.xls
[ranan@MPI0 ~]$ cat test | sed -n '/[ns]a.\.xls/p'
na1.xls
na2.xls
sa1.xls
sam.xls
usax.xls # 这个也被匹配到了,这里涉及之前说的位置匹配
[-]连字符表示字符区间
-只有出现在[-]里的时候才是元字符,在其他地方只是普通字符,表示字符-(它本身)。所以匹配-时是不需要转移的
案例
假设我们的需求是a后面不是跟任意字符了需要跟数字,也就是说不匹配上述的sam.xls
[0-9] 与[0123456789]完全等价
[ranan@MPI0 ~]$ cat test | sed -n '/[ns]a[1-9]\.xls/p'
na1.xls
na2.xls
sa1.xls
常用的字符区间
A-Z 匹配从A到Z的所有大写字母
a-z 匹配从a到z的所有小写字母
A-z 批评日从ASCII字符A到ASCII字符z之间的所有字母,这个模式不常用应为还包含[和^等在ASCII表中排列在Z和a之间的字符
在一个字符集合里可以给出多个字符区间,如果需要匹配任意字符,使用[A-Za-z]
[^] 排除
[^]在[]中表示排除指定的字符
当需要匹配很多的字符,仅仅排除很少的字符时使用
案例
假设我们需要匹配a后面不是数字的字符串
[ranan@MPI0 ~]$ cat test | sed -n '/[ns]a[^1-9]\.xls/p'
sam.xls
usal.xls
. 匹配任意单个字符
匹配除换行符\n之外的任意单个字符,包括本身。
如果指向匹配.,使用\.
元字符
元字符 | 说明 |
---|---|
\n | 空白元字符,换行符 |
\r | 空白元字符,回车符 |
\t | 空白元字符,Tab制表符 |
\f | 空白元字符,换页符 |
\v | 空白元字符,垂直制表符 |
\d | 类元字符(匹配一类字符),匹配任意一个数字字符等价于[0-9] |
\D | 类元字符,匹配任意一个非数字字符等价于[^0-9] |
\w | 任何一个字母数字字符或下划线等价于[a-zA-Z0-9_] |
\W | 等价于[^a-zA-Z0-9] |
\s | 任何一个空白字符,等价于[\f\n\r\t\v] |
\S | 任何一个非空白字符,等价于[^\f\n\r\t\v] |
匹配空行
\r\n匹配 回车+换行
windows把这个组合用作文本行的结束标志,所以搜索\r\n\r\n将匹配两个连续的行尾标志,也就是空行
Linux系统中,匹配空行只需要\n
理想的正则应该能够适应这两种情况,包含一个可选的\r和必须被匹配的\n
^$ 也可以表示空行
[\r]?\n[\r]?\n
[\r]定义了一个字符集合,该集合中只有元字符\r一个成员。
[\r]?和\r?在功能上等价。
[]常规用法是把多个字符定义成一个集合。
为了增加可读性和避免产生误解,让人一眼就能看出随后的元字符作用与谁,常常一个字符也定义成一个集合
POSIX字符类
POSIX是一种特殊的标准字符类集,JavaScript不支持
一般来说支持POSIX标准的正则表达式实现都支持POSIX字符类,细节方面可能与下述表述有细微差别
字符类 | 说明 |
---|---|
[:alnum:] | 任何一个字母或数字,[a-zA-Z0-9] |
[:alpha:] | 任何一个字母,[a-zA-Z] |
[:blank:] | 空白或制表符,[\t ] |
[:cntrl:] | ASCII控制字符,ASCII0-31,ASCII127 |
[:digit:] | 匹配十进制数字。[0-9] |
[:graph:] | 与[:print:]相似,但不包括空格字符 |
[:print:] | 任何一个可打印字符ASCII33-126,但多了空格字符 |
[:lower:] | 任何一个小写字母,[a-z] |
[:upper:] | 任何一个大写字母,[A-Z] |
[:space:] | 任何一个空白字符,包括空格,[\f\n\r\t\v ] |
[:xdigit:] | 任何一个十六进制数字。[a-fA-F0-9] |
注意POSIX字符类本身是带了[]的,假设匹配任意个字母[[:lower:][:upper:]]
控制匹配字符个数
字符 | 描述 | 说明 |
---|---|---|
+ | 匹配前面的子表达式一次或多次 | 贪婪型 |
* | 匹配前面的子表达式零次或多次 | 贪婪型 |
? | 匹配前面的子表达式零次或一次,匹配本身需转义 | |
重复从次数是非负整数 | ||
最小重复min次,最大重复max次 | 可省略其中一个 |
1.在字符集合[]里使用的时候,.和+这样的元字符等会被解释为普通字符,不需要转义
[ranan@MPI0 ~]$ echo "a+" | sed -n '/[0-9+]/p'
a+
[ranan@MPI0 ~]$ echo "a+" | sed -n '/[0-9\+]/p'
a+
2.{}是元字符,如果匹配自身需要转义,但是即使没有转义,大部分正则表达式也能正确处理
贪婪与懒惰
需求匹配 <b><\b>
标签中的文本
// 文本
This offer is not available to customers
living in <b>AK</b> and <b>HI</b>
//正则
<[Bb]>.*<[Bb]>
//结果 多了and
<b>AK</b> and <b>HI</b>
//正确写法
<[Bb]>.*?<[Bb]>
贪婪型的元字符会尽可能从一段文本的开头匹配到末尾,越多越好。
懒惰型写法是在贪婪型两次后面加上一个?
贪婪型量词 | 懒惰型量词 |
---|---|
* | *? |
+ | +? |
{n,}? |
位置匹配
元字符 | 说明 |
---|---|
\b | 单词边界,单词开头,单词结尾等 |
\B | 非单词边界 |
^ | 字符串边界元字符,代表字符串开头,[^才表示取反 |
$ | 字符串边界字符,代表字符串结尾 |
\b单词边界
\b 匹配的是字符之间的一个位置,一边是能够被\w匹配的字母数字字符和下划线,另一边是其他内容\W
单词边界就是单词和符号之间的边界
这里的单词可以是中文字符,英文字符,数字;符号可以是中文符号,英文符号,空格,制表符,换行
# is_没有被匹配因为is前面有\b,但是s和_都是\w所以之间没有\b就不会被匹配
echo "this is_" | sed -n '/\bis\b/p'
# s与(一个\w一个\W,所以它们之间有一个\b所以被匹配
echo "this is(" | sed -n '/\bis\b/p'
this is(
子表达式()
分组用法
{2,} 这里的次数是作用与前一个字符,而不是 
这个整体。
( ){2,}这样就表示空格至少出现两次了。
()
表示把括号里的部分看成一个整体,相当于进行分组
在匹配年份时,假设我们需要19或20开头的四位数(19|20)\d{2}
,不添加()意思是匹配19 或 20xx。
|
表示或的意思
反向引用匹配
反向引用:引用的是先前的子表达式,可以想成变量
案例
搜索连续重复出现的单词
[ ]+(\w+)[ ]+\1
这里(\w+)表示是一个子表达式,将其标识,最后使用\1表示对第一个表达式的反向引用,\1匹配内容与第一个分组匹配的内容一样,如果(\w+)匹配的是单词of那么\1匹配的也是of。
子表达式从1开始计数,在很多实现中第0个匹配(\0)可以用来代表整个正则表达式。
但是在不同的正则表达式实现中,语法差异很大。并且如果移动或编辑子表达式(子表达式位置会改变)等,可能会失效。比较新的正则表达式实现支持命名捕获:给某个子表达式起一个唯一的名字,用该名字(而不是相对位置)来引用这个子表达式。
还可以结合匹配的内容进行替换,常常用于调整文本格式,这部分先不介绍,目前我还没有使用到。
向前查看 ?=
之前学习的都是匹配文本,但有些时候需要用正则表达式来匹配文本的位置,也就是匹配到该文本,但不需要输出,只是定位作用。
向前查看指定了一个必须匹配但不用在结果中返回的模式,向前查看其实就是一个子表达式
语法
?= 开头的子表达式,需要匹配的文本跟在=后面
案例
假设需要在一系列URL地址中提取每个地址的协议部分
.+(?=:)
需要用:进行定位,用于定位:前面的内容,但不输出。
大多数主流的正则表达式实现都支持向前查看,支持向后查看的没有那么多
常用案例
IP地址
IP地址格式:XXX.XXX.XXX.XXX
每个字节的取值范围为0~255,以.分割
xxx可能的情况:
如果25开头的,那么第三位数为0~5
如果2开头,那么第二位数为0~4
以1开头的任意三位数
任意的一位数或者2位数
注意顺序|满足前面的条件就不会检查后面的了
((25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{1,2}).){3}(25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{1,2})
电子邮箱
电子邮箱的格式:第一个部分@第二个部分.第三个部分
(\w+\.)*\w+@(\w+\.)+[A-Za-z]+
第一个部分用于匹配用户名部分:可以是字母、数字、下划线、. (\w+\.)*\w+
\w+
匹配必须文本,(\w+\.)*
为了匹配ben.forta这种格式的用户名
第二个部分\w+
第三个部分匹配域名,域名全是字母 [A-Za-z]+
这种写法可以验证大部分电子邮件地址,但不是所有
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署