正则表达式
前言
本文详细介绍了正则表达式的基础内容
正则表达式基础内容
| RE 字符/范例 | 说明 | 
|---|---|
| \ | 跳脱/转义字符 | 
| 占位符 | 表示一个字符 | 
| ^word | ^表行首, 待匹配的字符串word在行首! | 
| …… grep -n '^#' re.txt | 显示行首为 #的行 | 
| word$ | $表行尾, 待匹配的字符串word在行尾! | 
| …… grep -n '!$' re.txt | 显示行尾为 !的行 | 
| . | 代表任意一个字符, 必须有一个字符 | 
| …… grep -n 'e.e' re.txt | 结果为 eveeeee e, 但不能是ee | 
| [] | 字符集合. 除 ^\-外, 其它特殊字符在中括号被认为是普通字符. 系统字符集可以包含其中如[\d] | 
| [^] | 中括号内的第一个 ^表示补集, | 
| …… grep -n '[(+*)]' re.txt | 匹配 (+*)中的一个字符. | 
| …… grep -n '[0-9]' re.txt | 搜寻含有任意数字的那一行.  中括号内的 -表连续(由编码决定), | 
| …… grep -n 'oo[^0-9]' re.txt | 排除结果 oo0-oo9, 可以是ooaoog等等 | 
| 数量符 | 跟在一个字符或组的后面, 重复该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 | 匹配 godgood等,gd | 
| *?+???{m,n}? | 让 *+?{m,n}变得非贪婪, 即匹配尽可能少的字符 | 
| …… <.*>匹配'<H1>title</H1>' | 会得到 '<H1>title</H1>'整个字符串,'<H1>' | 
| …… <.*?>匹配'<H1>title</H1>' | *?变得非贪婪, 会得到'<H1>'字符串 | 
| 逻辑分组 | 对字符进行分组和判断 | 
| () | 分组字符串 | 
| …… egrep 'A(xyz)+C' | 匹配A开头, C结尾, 中间有一个以上”xyz”的字符串, 如 AxyzCAxyzxyzxyzC | 
| \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 | 匹配 foofoo.(foo)b foo z,foobar | 
| \B | [^\b], 指定部分内容提取\w串 | 
| … py\B | 匹配 pythonpy3,pypy.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.txta123.txt
- re下 (string1|string2|string3). 如ls | egrep 'g(la|oo)d', 结果为gladgood
 
- 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.shex2.shex3.shex4.sh
- re下 ls | egrep "(ex[1-3]|ex4).sh", 结果为ex1.shex2.shex3.shex4.sh
 
- bash下, 有两种连续字符表示法 
- 简单总结, RE的功能远比bash自带的匹配符功能强大. 特别容易弄混的也就是 *?[^range]
参考资料
原创于 DRA&PHO