正则表达式

正则表达式

正则表达式是一些用来匹配和处理文本的字符串。
正则表达式是你所定义的模式模板(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.绝大多数正则表达式引擎默认只返回一个匹配结果
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之外的任意单个字符,包括本身。
如果指向匹配.,使用\.

所以匹配所有的字符可以用[\s\S]

元字符

元字符说明
\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}最小重复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,}{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,} 这里的次数是作用与前一个字符,而不是&nbsp这个整体。
( ){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]+

这种写法可以验证大部分电子邮件地址,但不是所有

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值