正则表达式
前言
本文详细介绍了正则表达式的基础内容
正则表达式基础内容
RE 字符/范例 | 说明 |
---|---|
\ |
跳脱/转义字符 |
占位符 | 表示一个字符 |
^word |
^ 表行首, 待匹配的字符串word 在行首! |
…… grep -n '^#' re.txt |
显示行首为 # 的行 |
word$ |
$ 表行尾, 待匹配的字符串word 在行尾! |
…… grep -n '!$' re.txt |
显示行尾为 ! 的行 |
. |
代表任意一个字符, 必须有一个字符 |
…… grep -n 'e.e' re.txt |
结果为 eve eee e e , 但不能是 ee |
[] |
字符集合. 除^ \ - 外, 其它特殊字符在中括号被认为是普通字符. 系统字符集可以包含其中如[\d] |
[^] |
中括号内的第一个^ 表示补集, |
…… grep -n '[(+*)]' re.txt |
匹配 ( + * ) 中的一个字符. |
…… grep -n '[0-9]' re.txt |
搜寻含有任意数字的那一行. 中括号内的- 表连续(由编码决定), |
…… grep -n 'oo[^0-9]' re.txt |
排除结果 oo0-oo9 , 可以是 ooa oog 等等 |
数量符 | 跟在一个字符或组的后面, 重复该RE字符或组若干次 |
* |
零个或多个的前一RE字符 |
…… grep -n 'ess*' re.py |
结果为 es (0次s), ess , esss |
…… .* |
表示任意字符 |
{m,n} |
连续m到n个的前一RE字符 |
…… {m,} |
连续m个及以上的前一RE字符 |
…… {m} |
连续m个的前一RE字符 |
…… grep -n 'go\{2,3\}g' re.txt |
结果为 goog (2次o), gooog (3次o). |
? |
零个或一个的前一RE字符, 等同于{0,1} |
…… egrep -n 'go?d' re.txt |
只能匹配gd 和god |
+ |
重复一个或以上的前一RE字符, 等同于{1,} |
…… egrep -n 'go+d' re.txt |
匹配god good 等, gd |
*? +? ?? {m,n}? |
让 * + ? {m,n} 变得非贪婪, 即匹配尽可能少的字符 |
…… <.*> 匹配'<H1>title</H1>' |
会得到 '<H1>title</H1>' 整个字符串, '<H1>' |
…… <.*?> 匹配'<H1>title</H1>' |
*? 变得非贪婪, 会得到 '<H1>' 字符串 |
逻辑分组 | 对字符进行分组和判断 |
() |
分组字符串 |
…… egrep 'A(xyz)+C' |
匹配A开头, C结尾, 中间有一个以上”xyz”的字符串, 如 AxyzC AxyzxyzxyzC |
\number |
反向引用, 引用编号为number 的分组() 匹配到字符串 |
…… (\d)abc\1 |
匹配结果 1abc1 或 5abc5 |
|
理解为或即可, 用来隔开多个正则表达式.- 譬如
egrep -n 'gd|good' re.txt
只能匹配gd
和good
- 譬如
egrep -n 'g(la|oo)d' re.txt
只能匹配glad
和good
正则表达式的兼容性问题
PCRE
即 Perl Compatible Regular Expression
常见的正则表达式记法,其实都源于Perl.
实际上,正则表达式是从Perl衍生出一个显赫的流派, 称为PCRE\d
\w
\s
之类的记法,就是这个流派的特征.
Python 的re库就是使用的PCRE. 其系统字符集如下:
系统字符集 | 含义 |
---|---|
\d |
digital, 数字字符, [0-9] |
\D |
非数字字符, [^\d] |
\s |
space, 空白字符, [ \t\r\n\f\v] |
\S |
非空白字符, [^\s] |
\w |
word, 单词字符, [A-Za-z0-9_] |
\W |
非单词字符, [^\w] |
\A |
仅匹配字符串开头 |
\Z |
仅匹配字符串结尾 |
\b |
提取指定的\w 串 |
… \bfoo\b |
匹配 foo foo. (foo) b foo z , foobar |
\B |
[^\b] , 指定部分内容提取\w 串 |
… py\B |
匹配 python py3 , py py. py! |
POSIX
linux是遵循POSIX标准的, 因此在linux下使用正则表达式时, 系统字符集如下:
系统字符集 | 含义 |
---|---|
[:alnum:] |
单词字符, [A-Za-z0-9_] |
[:alpha:] |
字母字符, [A-Za-z] |
[:ascii:] |
ASCII字符, [\x00-\x7F] |
[:blank:] |
空格字符, [ \t] |
[:cntrl:] |
控制键字符, [\x00-\x1F\x7F] |
[:digit:] |
数字字符, [0-9] |
[:graph:] |
非空字符, [\x21-\x7E] , [:blank:] 的补集 |
[:lower:] |
小写字母, [a-z] |
[:print:] |
可被打印的字符, [\x20-\x7E] |
[:punct:] |
所有标点符号, [][!"#$%&'()*+,./:;<=>?@\ ^_{}~-]丨` |
[:upper:] |
大写字母 [A-Z] |
[:space:] |
空白字符 [ \t\r\n\v\f] |
[:word:] |
字母字符 [A-Za-z_] |
[:xdigit:] |
16进制类型 [0-9A-Fa-f] |
BRE, 基础RE
即, Basic Regular Expression
BRE只定义了6组元字符:
[]
, 用于在多个字符中选定一个字符进行匹配.
, 用于匹配任意字符^
, 用于匹配时表示“非”的含义,还有一个用法是匹配行首$
, 用于匹配行尾*
, 零个或多个的前一RE字符\
, 跳脱/转义字符
在Linux/Unix常用工具中, grep vi sed都属于BRE这一派,
为了向前兼容并使用RE的一些新特性, 导致它的语法看起来比较奇怪. ()
{}
需要使用 \
转义后才有特殊含义.
如果直接使用 a{1,2}
, 只能去匹配 a{1,2}
字符串. 只有使用 a\{1,2\}
才能匹配为 a
和aa
.
另外, BRE一般不支持 +
?
(...|...)
\number
ERE, 扩展RE
即, Extention Regular Expression
ERE在BRE上增加了3组元字符的定义:
{}
用于表示重复匹配的次数. BRE中将{}
当作普通字符对待,必须加\
进行转义, 即\{\}
()
, 用于分组。BRE中只将()
当作普通字符对待,必须加\
进行转义,即\(\)
|
, 完全为ERE新增的多项匹配能力定义的,BRE无多项匹配能力,只将|
作普通字符对待\number
, ERE没有明确规定需要支持反向引用, 但不少工具都支持此功能
linux/unix下的RE表达式汇总
PCRE记法 | vi/vim | grep | egrep | awk | sed |
---|---|---|---|---|---|
* |
* |
* |
* |
* |
* |
+ |
\+ |
\+ |
+ |
+ |
\+ |
? |
\= |
\? |
? |
? |
\? |
{m,n} |
\{m,n} |
\{m,n\} |
{m,n} |
{m,n} |
\{m,n\} |
\b |
\< \> |
\< \> |
\< \> |
\< \> |
\y \< \> |
(…) |
\(…\) |
\(…\) |
(…) |
(…) |
(…) |
\1 \2 |
\1 \2 |
\1 \2 |
\1 \2 |
不支持 | \1 \2 |
注意:
- PCRE中常用
\b
来表示单词的起始或结束位, - Linux工具中, 通常用
\<
来匹配单词的起始位置, 用\>
来匹配单词的结束位置 sed
中的\y
可以同时匹配这两个位置。
与bash shell的一些容易弄混的区别
特殊字符 | bash shell中的含义 | RE中的含义 |
---|---|---|
* |
零个到多个任意字符 | 重复零个或多个前一RE字符 |
? |
一个任意字符 | 重复零个或一个前一RE字符 |
. |
运行代码 source |
一个任意字符 |
[0-9a-z] |
list内的一个字符 | list内的一个字符 |
[0-9] 的补集 |
[!0-9] () |
[^range] (! 在RE里是普通字符) |
{} |
{123,abc} 字符串匹配 |
{m,n} 重复m到n个前一RE字符 |
- 匹配
a
开头的任意文件- bash下
ls a*
- re下
ls | grep "^a.*"
- bash下
- 匹配string1或string2或更多之一字符串
- bash下
{string1,string2,string3}
. 如touch a{xyz,123}.txt
, 结果为axyz.txt
a123.txt
- re下
(string1|string2|string3)
. 如ls | egrep 'g(la|oo)d'
, 结果为glad
good
- bash下
- 连续字符匹配
- bash下, 有两种连续字符表示法
{0..9}
和[0-9]
, 支持[1-3a-z]
,不支持,{1..3a..z}
- bash下
touch {ex{1..3},ex4}.sh
或touch {ex{1..3},ex4}.sh
, 结果为ex1.sh
ex2.sh
ex3.sh
ex4.sh
- re下
ls | egrep "(ex[1-3]|ex4).sh"
, 结果为ex1.sh
ex2.sh
ex3.sh
ex4.sh
- bash下, 有两种连续字符表示法
- 简单总结, RE的功能远比bash自带的匹配符功能强大. 特别容易弄混的也就是
*
?
[^range]
参考资料
原创于 DRA&PHO