正则表达式介绍

Andrew_Notes / 2023-08-08 / 原文

一、正则表达式

简介

正则表达式,简写:re,全拼:(regular expression)
在某些地区,比如香港和台湾地区,叫正规表达式、规则表达式

正则一般给高级开发语言使用,比如Python,Go,C++,JAVA等,Linux运维中使用正则的是三剑客grep、sed和awk。Linux 三剑客要想工作得更高效,那么一定是离不开正则表达式的配合。

正则使用场景

  • 方便处理文本和字符串内容

  • 处理有规律的内容,比如身份证号,手机号(第一位是1),邮箱等。都可以拿正则去匹配

  • 搜索和替换

  • 数据验证

    比如,测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。

二、注意事项

1、不要混淆通配符与正则

区别内容 正则表达式 通配符
诞生的目标 匹配字符串 匹配参数或文件
支持的命令 grep/awk/sed/shell/其他开发语言 Bash命令、DOS命令等
符号的数量 所有的元字符 * {} ? [] [^]

通配符介绍见基础篇文档。

2、其他注意点

  • 1、Linux正则表达式是以行为单位进行处理的
  • 2、适用于三剑客命令,注意加引号,这里多以grep为例
  • 3、注意字符集,如果出现字符集问题,那么将字符集修改为C(LC_ALL=C 小概率事件)
  • 4、像素眼(留意空格,换行符,tab键)
  • 5、测试的时候,推荐使用grep -E或者egrep,因为过滤出来的内容会加颜色

三、正则表达式分类

正则的语法

# 正则表达式主要有两个部分:元字符和修饰符
/元字符/修饰符
/[a-z][0-9]{}()/ig

元字符:划分为基础正则和扩展正则。所谓扩展正则其实也是元字符的一部分,只不过在linux中,有些命令需要加上参数才能使用,所以被称作扩展正则。例如,grep -E即可支持扩展正则

  • 基础正则
  • 扩展正则
  • 其他语言正则

修饰符

  • 修饰符不是写在正则里面的,是写在正则外面的

基础正则(BRE)

字符 作用
^ ^oldboy,表示匹配以 oldboy 为开头的行
$ oldboy$,表示匹配以 oldboy 单词结尾的行
^$ 组合符,表示空行
. 点号,表示匹配任意一个且只有一个字符(除了换行符\n \r)
\ 转义字符,让有特殊含义的字符脱掉马甲,现出原形
* 匹配*前字符0次或0次以上的行
.* 组合符,匹配所有内容,包括空行
^.* 组合符,匹配以任意多个字符开头的内容
.*$ 组合符,匹配以任意多个字符结尾的内容
[abc] 匹配[ ]内的任意一个字符a或b或c;[abc]也可写成 [a-c]
[^abc] 匹配不包含后的任意字符,a或b或c,这里的“"表示对 [abc]的取反,此处的^不能用“!”替代

比如:

[a-zA-Z] 表示匹配所有单个大小写字母

[a-zA-Z0-9] 表示匹配所有字母加数字

扩展正则(ERE)

字符 作用
+ 匹配前一个字符1次或多次
[: /]+ 匹配括号内的:或/一次或多次
匹配前一个字符0次或1次
| 或者,用来匹配多个字符串
() 被括起来的表示一个整体,
()内的内容可以被后面的\n引用,n表示第n个括号的内容,例如:sed -nr 's#(.*)abc#\1#gp'
匹配前面内容n次,n 是一个非负整数
匹配前面内容最少n次,n 是一个非负整数
匹配前面内容最少n次,最多m次。m 和 n 均为非负整数,其中n <= m
匹配前面内容最多m次

grep -E即可支持扩展正则

修饰符

修饰符也称为标记,正则表达式的标记用于指定额外的匹配策略。

标记不写在正则表达式里,标记位于表达式之外,格式如下:

/pattern/flags
/正则表达式/标记

正则表达式常用的修饰符:

修饰符 含义 描述
i ignore - 不区分大小写 将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别。
g global - 全局匹配 查找所有的匹配项
m multi line - 多行匹配 使边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾
s 特殊字符圆点 . 中包含换行符 \n 默认情况下的圆点 . 是匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。

元字符

在正则表达式中,除了前面列出的基础正则和扩展正则,元字符还有很多。举例如下:

# \n:换行符
[root@m01 ~]#  echo -e '1\n2\n3'
1
2
3
[root@m01 ~]#  echo -e '1\x0a2\x0a3'
1
2
3

# \r:回车
[root@m01 ~]#  echo -e '1\r2'
2

# \t:tab 水平制表符
[root@m01 ~]#  echo -e '1\t2\t3'
1	2	3

# \v:垂直制表符
[root@m01 ~]#  echo -e '1\v2\v3'
1
 2
  3

# \f:换页符

# \b:匹配单词边界 比如,\bzls\b 表示只匹配单词zls
[root@m01 ~]# useradd zls111
[root@m01 ~]# grep 'zls' /etc/passwd
zls:x:1000:1000::/home/zls:/bin/bash
zls111:x:1002:1002::/home/zls111:/bin/bash

[root@m01 ~]# grep '\bzls\b' /etc/passwd
zls:x:1000:1000::/home/zls:/bin/bash

[root@m01 ~]# grep 'zls\b' /etc/passwd
zls:x:1000:1000::/home/zls:/bin/bash
111zls:x:1003:1003::/home/111zls:/bin/bash

# \B:匹配非单词的边界
[root@m01 ~]# grep 'zls\B' /etc/passwd   //只匹配了zls111中的zls,不匹配单独的zls单词
zls111:x:1002:1002::/home/zls111:/bin/bash

# \d:匹配单个数字字符(需使用grep -P支持),等价于[0-9]
[root@lb01 ~]# grep -P [0-9] 1.txt
My QQ is 133411023.
not 1334110023.

[root@lb01 ~]# grep -P '\d' 1.txt
My QQ is 133411023.
not 1334110023.

[root@lb01 ~]# grep -Po '\d' 1.txt
[root@lb01 ~]# grep -Po '[0-9]' 1.txt


# \D:匹配一个非数字(需使用grep -P支持),等价于[^0-9]
[root@m01 ~]# grep -Po '\D' 1.txt
[root@m01 ~]# grep -Po '[^0-9]' 1.txt

# \w:匹配字母,数字与下划线,等价于[A-Za-z0-9_]
[root@m01 ~]# grep -o '\w' 1.txt

# \W:匹配非字母,数字与下划线(等价于[^A-Za-z0-9_])
[root@m01 ~]# grep -o '\W' 1.txt

# \s:匹配任何空白字符,包括空格、制表符、换页符等等 等价于 [ \f\n\r\t\v]
# \S:匹配任何非空白字符,等价于 [^ \f\n\r\t\v] 这俩也需要grep -P支持

# 把下面手机号中间四位变成*

[root@m01 ~]# cat 1.txt
13081761354
13081761351
13081761352
13081761353
13081761355
13081761356
[root@m01 ~]# sed -nr 's#([0-9]{3})([0-9]{4})([0-9]{4})#\1****\3#gp' 1.txt
130****1354
130****1351
130****1352
130****1353
130****1355
130****1356

[root@m01 ~]# awk '{gsub(/8176/,"*");print $0}' 1.txt
130*1354
130*1351
130*1352
130*1353
130*1355
130*1356
[root@m01 ~]# awk '{gsub(/8176/,"****");print $0}' 1.txt   
130****1354
130****1351
130****1352
130****1353
130****1355
130****1356

附表:各语言元字符支持情况

字符 说明 Basic RegEx Extended RegEx python RegEx Perl regEx
转义 \ \ \ \
^ 匹配行首,例如'dog'匹配以字符串dog开头的行(注意:awk 指令中,''则是匹配字符串的开始) ^ ^ ^ ^
$ 匹配行尾,例如:'、dog$'匹配以字符串 dog 为结尾的行(注意:awk 指令中,'$'则是匹配字符串的结尾) $ $ $ $
$ 匹配空行 $ $ $ $
string$ 匹配行,例如:'dog$'匹配只含一个字符串 dog 的行 string$ string$ string$ string$
< 匹配单词,例如:'<frog' (等价于'\bfrog'),匹配以 frog 开头的单词 < < 不支持 不支持(但可以使用\b来匹配单词,例如:'\bfrog')
> 匹配单词,例如:'frog>'(等价于'frog\b '),匹配以 frog 结尾的单词 > > 不支持 不支持(但可以使用\b来匹配单词,例如:'frog\b')
匹配一个单词或者一个特定字符,例如:''(等价于'\bfrog\b')、'' 不支持 不支持(但可以使用\b来匹配单词,例如:'\bfrog\b'
() 匹配表达式,例如:不支持'(frog)' 不支持(但可以使用,如:dogdog () () ()
匹配表达式,例如:不支持'(frog)' 不支持(同()) 不支持(同()) 不支持(同())
匹配前面的子表达式 0 次或 1 次(等价于{0,1}),例如:where(is)?能匹配"where" 以及"whereis" 不支持(同?)
? 匹配前面的子表达式 0 次或 1 次(等价于'{0,1}'),例如:'whereisis? '能匹配 "where"以及"whereis" ? 不支持(同?) 不支持(同?) 不支持(同?)
? 当该字符紧跟在任何一个其他限制符(*, +, ?, {n},{n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个"o",而 'o+' 将匹配所有 'o' 不支持 不支持 不支持 不支持
. 匹配除换行符('\n')之外的任意单个字符(注意:awk 指令中的句点能匹配换行符) . .(如果要匹配包括“\n”在内的任何一个字符,请使用:'($)|(.) . .(如果要匹配包括“\n”在内的任何一个字符,请使用:' [.\n] '
* 匹配前面的子表达式 0 次或多次(等价于{0, }),例如:zo* 能匹配 "z"以及 "zoo" * * * *
+ 匹配前面的子表达式 1 次或多次(等价于'{1, }'),例如:'whereisis+ '能匹配 "whereis"以及"whereisis" + 不支持(同+) 不支持(同+) 不支持(同+)
+ 匹配前面的子表达式 1 次或多次(等价于{1, }),例如:zo+能匹配 "zo"以及 "zoo",但不能匹配 "z" 不支持(同+) + + +
n 必须是一个 0 或者正整数,匹配子表达式 n 次,例如:zo{2}能匹配 不支持(同{n})
"zooz",但不能匹配 "Bob"n 必须是一个 0 或者正整数,匹配子表达式大于等于 n次,例如:go 不支持(同{n,})
能匹配 "good",但不能匹配 godm 和 n 均为非负整数,其中 n <= m,最少匹配 n 次且最多匹配 m 次 ,例如:o{1,3}将配"fooooood" 中的前三个 o(请注意在逗号和两个数之间不能有空格) 不支持(同{n,m})
x|y 匹配 x 或 y,例如: 不支持'z|(food)' 能匹配 "z" 或"food";'(z|f)ood' 则匹配"zood" 或 "food" 不支持(同x|y) x|y x|y x|y
[0-9] 匹配从 0 到 9 中的任意一个数字字符(注意:要写成递增) [0-9] [0-9] [0-9] [0-9]
[xyz] 字符集合,匹配所包含的任意一个字符,例如:'[abc]'可以匹配"lay" 中的 'a'(注意:如果元字符,例如:. *等,它们被放在[ ]中,那么它们将变成一个普通字符) [xyz] [xyz] [xyz] [xyz]
[xyz] 负值字符集合,匹配未包含的任意一个字符(注意:不包括换行符),例如:'[abc]' 可以匹配 "Lay" 中的'L'(注意:[xyz]在awk 指令中则是匹配未包含的任意一个字符+换行符) [xyz] [xyz] [xyz] [xyz]
[A-Za-z] 匹配大写字母或者小写字母中的任意一个字符(注意:要写成递增) [A-Za-z] [A-Za-z] [A-Za-z] [A-Za-z]
[A-Za-z] 匹配除了大写与小写字母之外的任意一个字符(注意:写成递增) [A-Za-z] [A-Za-z] [A-Za-z] [A-Za-z]
\d 匹配从 0 到 9 中的任意一个数字字符(等价于 [0-9]) 不支持 不支持 \d \d
\D 匹配非数字字符(等价于 [0-9]) 不支持 不支持 \D \D
\S 匹配任何非空白字符(等价于[\f\n\r\t\v]) 不支持 不支持 \S \S
\s 匹配任何空白字符,包括空格、制表符、换页符等等(等价于[ \f\n\r\t\v]) 不支持 不支持 \s \s
\W 匹配任何非单词字符 (等价于[A-Za-z0-9_]) \W \W \W \W
\w 匹配包括下划线的任何单词字符(等价于[A-Za-z0-9_]) \w \w \w \w
\B 匹配非单词边界,例如:'er\B' 能匹配 "verb" 中的'er',但不能匹配"never" 中的'er' \B \B \B \B
\b 匹配一个单词边界,也就是指单词和空格间的位置,例如: 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的'er' \b \b \b \b
\t 匹配一个横向制表符(等价于 \x09和 \cI) 不支持 不支持 \t \t
\v 匹配一个垂直制表符(等价于 \x0b和 \cK) 不支持 不支持 \v \v
\n 匹配一个换行符(等价于 \x0a 和\cJ) 不支持 不支持 \n \n
\f 匹配一个换页符(等价于\x0c 和\cL) 不支持 不支持 \f \f
\r 匹配一个回车符(等价于 \x0d 和\cM) 不支持 不支持 \r \r
\ 匹配转义字符本身"" \ \ \ \
\cx 匹配由 x 指明的控制字符,例如:\cM匹配一个Control-M 或回车符,x 的值必须为A-Z 或 a-z 之一,否则,将 c 视为一个原义的 'c' 字符 不支持 不支持 \cx
\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长,例如:'\x41' 匹配 "A"。'\x041' 则等价于'\x04' & "1"。正则表达式中可以使用 ASCII 编码 不支持 不支持 \xn
\num 匹配 num,其中 num是一个正整数。表示对所获取的匹配的引用 不支持 \num \num
[:alnum:] 匹配任何一个字母或数字([A-Za-z0-9]),例如:'[[:alnum:]] ' [:alnum:] [:alnum:] [:alnum:] [:alnum:]
[:alpha:] 匹配任何一个字母([A-Za-z]), 例如:' [[:alpha:]] ' [:alpha:] [:alpha:] [:alpha:] [:alpha:]
[:digit:] 匹配任何一个数字([0-9]),例如:'[[:digit:]] ' [:digit:] [:digit:] [:digit:] [:digit:]
[:lower:] 匹配任何一个小写字母([a-z]), 例如:' [[:lower:]] ' [:lower:] [:lower:] [:lower:] [:lower:]
[:upper:] 匹配任何一个大写字母([A-Z]) [:upper:] [:upper:] [:upper:] [:upper:]
[:space:] 任何一个空白字符: 支持制表符、空格,例如:' [[:space:]] ' [:space:] [:space:] [:space:] [:space:]
[:blank:] 空格和制表符(横向和纵向),例如:'[[:blank:]]'ó'[\s\t\v]' [:blank:] [:blank:] [:blank:] [:blank:]
[:graph:] 任何一个可以看得见的且可以打印的字符(注意:不包括空格和换行符等),例如:'[[:graph:]] ' [:graph:] [:graph:] [:graph:] [:graph:]
[:print:] 任何一个可以打印的字符(注意:不包括:[:cntrl:]、字符串结束符'\0'、EOF 文件结束符(-1), 但包括空格符号),例如:'[[:print:]] ' [:print:] [:print:] [:print:] [:print:]
[:cntrl:] 任何一个控制字符(ASCII 字符集中的前 32 个字符,即:用十进制表示为从 0 到31,例如:换行符、制表符等等),例如:' [[:cntrl:]]' [:cntrl:] [:cntrl:] [:cntrl:] [:cntrl:]
[:punct:] 任何一个标点符号(不包括:[:alnum:]、[:cntrl:]、[:space:]这些字符集) [:punct:] [:punct:] [:punct:] [:punct:]
[:xdigit:] 任何一个十六进制数(即:0-9,a-f,A-F) [:xdigit:] [:xdigit:] [:xdigit:] [:xdigit:]