layout: post
title: 正则表达式基础知识
categories:
2014-04-03 13:49:31
整理网络上关于正则表达式异同的资料, 加以补充.
正则表达式是基于样式匹配的文本处理技术的关键所在. 想要在编写文本处理工具方面驾轻就熟, 就必须对正则表达式有个基本的了解.
正则表达式:在计算机科学中, 是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串. 正则表达式是一种用于文本匹配的形式小巧、具有高针对性的编程语言, 在很多文本编辑器或其他工具里, 正则表达式通常被用来检索和/或替换那些符合某个模式的文本内容. 许多程序设计语言都支持利用正则表达式进行字符串操作. 例如, 在Perl中就内建了一个功能强大的正则表达式引擎. 正则表达式通常缩写成“regex”, 单数有regexp、regex, 复数有regexps、regexes、regexen.
正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的. 由于起源于Unix系统, 因此很多语法规则是一样的. 但是随着逐渐发展, 扩展出以下几个类型.
一、正则表达式分类
- 基本的正则表达式(Basic Regular Expression, 又叫 Basic RegEx, 简称 BREs)
- 扩展的正则表达式(Extended Regular Expression, 又叫 Extended RegEx, 简称 EREs)
- Perl的正则表达式(Perl Regular Expression, 又叫 Perl RegEx, 简称 PREs)
只有掌握了正则表达式, 才能全面地掌握 Linux 下的常用文本工具(例如:grep、egrep、GUN sed、 Awk 等) 的用法
二、Linux 中常用文本工具与正则表达式的关系
常握 Linux 下几种常用文本工具的特点, 对于我们更好的使用正则表达式是很有帮助的.
grep, egrep 正则表达式特点
grep 支持:BREs、EREs、PREs 正则表达式
- grep 指令后不跟任何参数, 则表示要使用 BREs
- grep 指令后跟 "-E" 参数, 则表示要使用 EREs
- grep 指令后跟 "-P" 参数, 则表示要使用 PREs
egrep 支持:EREs、PREs 正则表达式
- egrep 指令后不跟任何参数, 则表示要使用 EREs
- egrep 指令后跟 "-P" 参数, 则表示要使用 PREs
grep 与 egrep 正则匹配文件, 处理文件方法
- grep 与 egrep 的处理对象:文本文件
- grep 与 egrep 在处理文本文件时, 是按行处理的
- grep 与 egrep 的处理过程:查找文本文件中是否含要查找的 “关键字”(关键字可以是正则表达式), 如果含有要查找的 ”关健字“, 那么默认返回该文本文件中包含该”关健字“的该行的内容, 并在标准输出中显示出来, 除非使用了“>" 重定向符号
sed 正则表达式特点
- sed 支持:BREs、EREs
- sed 指令默认是使用"BREs"
- sed 命令参数"-r" , 则表示要使用"EREs"
- sed 功能与作用
- sed 处理的对象:文本文件
- sed 在处理文本文件的时候, 也是按行处理的
- sed 处理操作:对文本文件的内容进行 --- 查找、替换、删除、增加等操作
Awk(gawk)正则表达式特点
- Awk 文本工具支持:EREs
- Awk 文本工具处理文本的特点
- awk 处理的对象:文本文件
- awk 处理操作:主要是对列进行操作
三、Linux中常见3种类型正则表达式比较
- 基本组成部分
- 元字符(meta character)是一种Perl风格的正则表达式, 只有一部分文本处理工具支持它, 并不是所有的文本处理工具都支持.
- POSIX字符类是一个形如[:...:]的特殊元序列(meta sequence), 可以用于匹配特定的字符范围.
<table><caption>常用Linux/Unix工具中的表示法</caption>
<tr>
<th style="text-align:center;">PCRE记法</th>
<th style="text-align:center;">vi/vim</th>
<th style="text-align:center;">grep</th>
<th style="text-align:center;">awk</th>
<th style="text-align:center;">sed</th>
</tr>
<tr>
<td style="text-align:center;">*</td>
<td style="text-align:center;">*</td>
<td style="text-align:center;">*</td>
<td style="text-align:center;">*</td>
<td style="text-align:center;">*</td>
</tr>
<tr>
<td style="text-align:center;">+</td>
<td style="text-align:center;">\+</td>
<td style="text-align:center;">\+</td>
<td style="text-align:center;">+</td>
<td style="text-align:center;">\+</td>
</tr>
<tr>
<td style="text-align:center;">?</td>
<td style="text-align:center;">\=</td>
<td style="text-align:center;">\?</td>
<td style="text-align:center;">?</td>
<td style="text-align:center;">\?</td>
</tr>
<tr>
<td style="text-align:center;">{m,n}</td>
<td style="text-align:center;">\{m,n}</td>
<td style="text-align:center;">\{m,n\}</td>
<td style="text-align:center;">{m,n}</td>
<td style="text-align:center;">\{m,n\}</td>
</tr>
<tr>
<td style="text-align:center;">\b</td>
<td style="text-align:center;">\< \></td>
<td style="text-align:center;">\< \></td>
<td style="text-align:center;">\< \></td>
<td style="text-align:center;">\y \< \></td>
</tr>
<tr>
<td style="text-align:center;">(…)</td>
<td style="text-align:center;">\\((…\)\)</td>
<td style="text-align:center;">\\((…\)\)</td>
<td style="text-align:center;">(…)</td>
<td style="text-align:center;">(…)</td>
</tr>
<tr>
<td style="text-align:center;">(…|…)</td>
<td style="text-align:center;">\(\backslash(\)…|…\(\backslash)\)</td>
<td style="text-align:center;">\(\backslash(\)…|…\(\backslash)\)</td>
<td style="text-align:center;">(…|…)</td>
<td style="text-align:center;">(…|…)</td>
</tr>
<tr>
<td style="text-align:center;">\1 \2</td>
<td style="text-align:center;">\1 \2</td>
<td style="text-align:center;">\1 \2</td>
<td style="text-align:center;">不支持</td>
<td style="text-align:center;">\1 \2</td>
</tr>
</table><table><caption>几种POSIX流派的说明</caption>
<tr>
<th style="text-align:left;">流派</th>
<th style="text-align:left;">说明</th>
<th style="text-align:left;">工具</th>
</tr>
<tr>
<td style="text-align:left;">BRE</td>
<td style="text-align:left;">( ) { }都必须转义使用, 不支持+ ? |</td>
<td style="text-align:left;">grep、sed、vi(但vi支持这些多选结构和反向引用)</td>
</tr>
<tr>
<td style="text-align:left;">GNU BRE</td>
<td style="text-align:left;">( ){ } + ? |都必须转义使用</td>
<td style="text-align:left;">GNU grep、GNU sed</td>
</tr>
<tr>
<td style="text-align:left;">ERE</td>
<td style="text-align:left;">元字符不必转义, + ? ( ) { } |可以直接使用, \1、\2的支持不确定</td>
<td style="text-align:left;">egrep、awk</td>
</tr>
<tr>
<td style="text-align:left;">GNU ERE</td>
<td style="text-align:left;">元字符不必转义, + ? ( ) { } |可以直接使用, 支持\1、\2</td>
<td style="text-align:left;">grep –E、GNU awk</td>
</tr>
</table><table><caption>常见正则表达式比较</caption>
<tr>
<th style="text-align:center;">字符</th>
<th style="text-align:center;">说明</th>
<th style="text-align:center;">BRE</th>
<th style="text-align:center;">ERE</th>
<th style="text-align:center;">PRE</th>
<th style="text-align:center;">python</th>
</tr>
<tr>
<td style="text-align:center;">.</td>
<td style="text-align:left;">除换行符'\n'之外的任意单个字符(awk中可匹配换行符)</td>
<td style="text-align:center;">.</td>
<td style="text-align:center;">. 匹配含\n在内的任一字符用(^$)|(.)</td>
<td style="text-align:center;">. 匹配含\n在内的任一字符可用[.\n]</td>
<td style="text-align:center;">.</td>
</tr>
<tr>
<td style="text-align:center;">\</td>
<td style="text-align:left;">转义符,将下一个字符标记为一个特殊字符、一个原义字符、一个向后引用或一个八进制转义符</td>
<td colspan="4" style="text-align:center;">\</td>
</tr>
<tr>
<td style="text-align:center;">\\</td>
<td style="text-align:left;">转义字符本身</td>
<td colspan="4" style="text-align:center;">\\</td>
</tr>
<tr>
<td style="text-align:center;">^</td>
<td style="text-align:left;">行首(awk中匹配字符串的开始)</td>
<td colspan="4" style="text-align:center;">^</td>
</tr>
<tr>
<td style="text-align:center;">$</td>
<td style="text-align:left;">行尾(awk中匹配字符串的结尾)</td>
<td colspan="4" style="text-align:center;">$</td>
</tr>
<tr>
<td style="text-align:center;">^$</td>
<td style="text-align:left;">空行</td>
<td colspan="4" style="text-align:center;">^$</td>
</tr>
<tr>
<td style="text-align:center;">^str$</td>
<td style="text-align:left;">行</td>
<td colspan="4" style="text-align:center;">^str$</td>
</tr>
<tr>
<td style="text-align:center;">\<</td>
<td style="text-align:left;">单词开头</td>
<td colspan="2" style="text-align:center;">\<</td>
<td rowspan="3" style="text-align:center;">不支持,用\b代替</td>
<td rowspan="3" style="text-align:center;">不支持</td>
</tr>
<tr>
<td style="text-align:center;">\></td>
<td style="text-align:left;">单词结尾</td>
<td colspan="2" style="text-align:center;">\></td>
</tr>
<tr>
<td style="text-align:center;">\<x\></td>
<td style="text-align:left;">一个单词或一个特定字符</td>
<td colspan="2" style="text-align:center;">\<x\></td>
</tr>
<tr>
<td style="text-align:center;">()</td>
<td style="text-align:left;">表达式</td>
<td style="text-align:center;">不支持,用\(\backslash(\backslash)\)代替</td>
<td colspan="3" style="text-align:center;">()</td>
</tr>
<tr>
<td style="text-align:center;">\(\backslash(\backslash)\)</td>
<td style="text-align:left;">表达式</td>
<td style="text-align:center;">\(\backslash(\backslash)\)</td>
<td colspan="3" style="text-align:center;">不支持,同()</td>
</tr>
<tr>
<td style="text-align:center;">*</td>
<td style="text-align:left;">前面的子表达式0或多次(等价于{0,})</td>
<td colspan="4" style="text-align:center;">*</td>
</tr>
<tr>
<td style="text-align:center;">+</td>
<td style="text-align:left;">前面的子表达式1或多次(等价于{1,})</td>
<td style="text-align:center;">不支持,同\+</td>
<td colspan="3" style="text-align:center;">+</td>
</tr>
<tr>
<td style="text-align:center;">\+</td>
<td style="text-align:left;">前面的子表达式1或多次(等价于\{1,\})</td>
<td style="text-align:center;">\+</td>
<td colspan="3" style="text-align:center;">不支持,同+</td>
</tr>
<tr>
<td style="text-align:center;">?</td>
<td style="text-align:left;">前面的子表达式0或1次(等价于{0,1})</td>
<td style="text-align:center;">不支持,同\?</td>
<td colspan="3" style="text-align:center;">?</td>
</tr>
<tr>
<td style="text-align:center;">\?</td>
<td style="text-align:left;">前面的子表达式0或1次(等价于\{0,1\})</td>
<td style="text-align:center;">\?</td>
<td colspan="3" style="text-align:center;">不支持,同?</td>
</tr>
<tr>
<td style="text-align:center;">{n}</td>
<td style="text-align:left;">前面的子表达式n次,n为0或正整数</td>
<td style="text-align:center;">不支持,同\{n\}</td>
<td colspan="3" style="text-align:center;">{n}</td>
</tr>
<tr>
<td style="text-align:center;">{n,}</td>
<td style="text-align:left;">前面的子表达式大于等于n次</td>
<td style="text-align:center;">不支持,同\{n,\}</td>
<td colspan="3" style="text-align:center;">{n,}</td>
</tr>
<tr>
<td style="text-align:center;">{n,m}</td>
<td style="text-align:left;">前面的子表达式最少n次且最多m次,n<=m(逗号前后不能有空格)</td>
<td style="text-align:left;">不支持同\{n,m\}</td>
<td colspan="3" style="text-align:center;">{n,m}</td>
</tr>
<tr>
<td style="text-align:center;">\|</td>
<td style="text-align:left;">交替匹配|两边的任意一项</td>
<td style="text-align:left;">不支持,同\|</td>
<td colspan="3" style="text-align:center;">|</td>
</tr>
<tr>
<td style="text-align:center;">x|y</td>
<td style="text-align:left;">x或y</td>
<td style="text-align:left;">不支持,同x\|y</td>
<td colspan="3" style="text-align:center;">x|y</td>
</tr>
<tr>
<td style="text-align:center;">[]</td>
<td style="text-align:left;">包含在[字符]之中的任意一个字符</td>
<td colspan="4" style="text-align:center;">[]</td>
</tr>
<tr>
<td style="text-align:center;">[^]</td>
<td style="text-align:left;">[^字符]之外的任一字符</td>
<td colspan="4" style="text-align:center;">[^]</td>
</tr>
<tr>
<td style="text-align:center;">[-]</td>
<td style="text-align:center;">[]中指定范围内的任一字符,要写成递增</td>
<td colspan="4" style="text-align:center;">[-]</td>
</tr>
<tr>
<td style="text-align:center;">[0-9]</td>
<td style="text-align:left;">0到9中的任一数字字符(要写成递增)</td>
<td colspan="4" style="text-align:center;">[0-9]</td>
</tr>
<tr>
<td style="text-align:center;">[xyz]</td>
<td style="text-align:left;">字符集合,匹配所包含的任意一个字符(被放在[]中的元字符将变为普通字符)</td>
<td colspan="4" style="text-align:center;">[xyz]</td>
</tr>
<tr>
<td style="text-align:center;">[^xyz]</td>
<td style="text-align:left;">非字符集合,匹配未包含的任意一个字符(不包括换行符,awk中则匹配未包含的任意一个字符和换行符)</td>
<td colspan="4" style="text-align:center;">[^xyz]</td>
</tr>
<tr>
<td style="text-align:center;">[A-Za-z]</td>
<td style="text-align:left;">大写或小写字母中的任意一个字符(要写成递增)</td>
<td colspan="4" style="text-align:center;">[A-Za-z]</td>
</tr>
<tr>
<td style="text-align:center;">[^A-Za-z]</td>
<td style="text-align:left;">除大写与小写字母之外的任意一个字符(写成递增)</td>
<td colspan="4" style="text-align:center;">[^A-Za-z]</td>
</tr>
<tr>
<td style="text-align:center;">?</td>
<td style="text-align:center;">紧跟在任何一个其他限制符(* + ? {n} {n,} {n,m})后面时,使用非贪婪匹配模式.非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配</td>
<td colspan="4" style="text-align:center;">不支持</td>
</tr>
<tr>
<th colspan="6" style="text-align:center;">元字符</th>
</tr>
<tr>
<td style="text-align:center;">\w</td>
<td style="text-align:left;">包括下划线的任何单词字符(等价于[A-Za-z0-9_])</td>
<td colspan="4" style="text-align:center;">\w</td>
</tr>
<tr>
<td style="text-align:center;">\W</td>
<td style="text-align:left;">任何非单词字符(等价于[^A-Za-z0-9_])</td>
<td colspan="4" style="text-align:center;">\W</td>
</tr>
<tr>
<td style="text-align:center;">\b</td>
<td style="text-align:left;">单词边界,指单词和空格间的位置</td>
<td colspan="4" style="text-align:center;">\b</td>
</tr>
<tr>
<td style="text-align:center;">\B</td>
<td style="text-align:left;">非单词边界</td>
<td colspan="4" style="text-align:center;">\B</td>
</tr>
<tr>
<td style="text-align:center;">\d</td>
<td style="text-align:left;">0到9中的任一数字字符(等价于[0-9])</td>
<td rowspan="12" colspan="2" style="text-align:center;">不支持</td>
<td colspan="2" style="text-align:center;">\d</td>
</tr>
<tr>
<td style="text-align:center;">\D</td>
<td style="text-align:left;">非数字字符(等价于[^0-9])</td>
<td colspan="2" style="text-align:center;">\D</td>
</tr>
<tr>
<td style="text-align:center;">\s</td>
<td style="text-align:left;">任何空白字符,包括空格,制表符,换页符等等(等价于[\f\n\r\t\v])</td>
<td colspan="2" style="text-align:center;">\s</td>
</tr>
<tr>
<td style="text-align:center;">\S</td>
<td style="text-align:left;">任何非空白字符(等价于[^\f\n\r\t\v])</td>
<td colspan="2" style="text-align:center;">\S</td>
</tr>
<tr>
<td style="text-align:center;">\t</td>
<td style="text-align:left;">一个横向制表符(等价于\x09和\cI)</td>
<td colspan="2" style="text-align:center;">\t</td>
</tr>
<tr>
<td style="text-align:center;">\v</td>
<td style="text-align:left;">一个垂直制表符(等价于\x0b和\cK)</td>
<td colspan="2" style="text-align:center;">\v</td>
</tr>
<tr>
<td style="text-align:center;">\n</td>
<td style="text-align:left;">一个换行符(等价于\x0a和\cJ)</td>
<td colspan="2" style="text-align:center;">\n</td>
</tr>
<tr>
<td style="text-align:center;">\f</td>
<td style="text-align:left;">一个换页符(等价于\x0c和\cL)</td>
<td colspan="2" style="text-align:center;">\f</td>
</tr>
<tr>
<td style="text-align:center;">\r</td>
<td style="text-align:left;">一个回车符(等价于\x0d和\cM)</td>
<td colspan="2" style="text-align:center;">\r</td>
</tr>
<tr>
<td style="text-align:center;">\cx</td>
<td style="text-align:left;">由x指明的控制字符,x的值必须为A-Z或a-z之一,否则将c视为一个原义的c字符</td>
<td colspan="2" style="text-align:center;">\cx</td>
</tr>
<tr>
<td style="text-align:center;">\xn</td>
<td style="text-align:left;">n为十六进制转义值,必须为确定的两个数字长</td>
<td colspan="2" style="text-align:center;">\xn</td>
</tr>
<tr>
<td style="text-align:center;">\num</td>
<td style="text-align:left;">num为正整数,表示对所获取的匹配的引用</td>
<td colspan="2" style="text-align:center;">\num</td>
</tr>
<tr>
<th colspan="6" style="text-align:center;">POSIX字符类</th>
</tr>
<tr>
<td style="text-align:center;">[:lower:]</td>
<td style="text-align:left;">任何一个小写字母([a-z])</td>
<td colspan="4" style="text-align:center;">[:lower:]</td>
</tr>
<tr>
<td style="text-align:center;">[:upper:]</td>
<td style="text-align:left;">任何一个大写字母([A-Z])</td>
<td colspan="4" style="text-align:center;">[:upper:]</td>
</tr>
<tr>
<td style="text-align:center;">[:alpha:]</td>
<td style="text-align:left;">任何一个字母([A-Za-z])</td>
<td colspan="4" style="text-align:center;">[:alpha:]</td>
</tr>
<tr>
<td style="text-align:center;">[:digit:]</td>
<td style="text-align:left;">任何一个数字([0-9])</td>
<td colspan="4" style="text-align:center;">[:digit:]</td>
</tr>
<tr>
<td style="text-align:center;">[:alnum:]</td>
<td style="text-align:left;">任何一个字母或数字([A-Za-z0-9])</td>
<td colspan="4" style="text-align:center;">[:alnum:]</td>
</tr>
<tr>
<td style="text-align:center;">[:space:]</td>
<td style="text-align:left;">任何一个空白字符(制表符,空格)</td>
<td colspan="4" style="text-align:center;">[:space:]</td>
</tr>
<tr>
<td style="text-align:center;">[:blank:]</td>
<td style="text-align:left;">空格和制表符(横向和纵向)</td>
<td colspan="4" style="text-align:center;">[:blank:]</td>
</tr>
<tr>
<td style="text-align:center;">[:graph:]</td>
<td style="text-align:left;">任何一个可见的且可以打印的字符(不包括空格和换行符等)</td>
<td colspan="4" style="text-align:center;">[:graph:]</td>
</tr>
<tr>
<td style="text-align:center;">[:cntrl:]</td>
<td style="text-align:left;">任何一个控制字符(ASCII字符集中的前32个字符,用十进制表示为0到31,如换行符,制表符等)</td>
<td colspan="4" style="text-align:center;">[:cntrl:]</td>
</tr>
<tr>
<td style="text-align:center;">[:print:]</td>
<td style="text-align:left;">任何一个可以打印的字符(不包括[:cntrl:],字符串结束符\0,EOF文件结束符-1,但包括空格)</td>
<td colspan="4" style="text-align:center;">[:print:]</td>
</tr>
<tr>
<td style="text-align:center;">[:punct:]</td>
<td style="text-align:left;">任何一个标点符号(不包括[:alnum:] [:cntrl:] [:space:]字符集)</td>
<td colspan="4" style="text-align:center;">[:punct:]</td>
</tr>
<tr>
<td style="text-align:center;">[:xdigit:]</td>
<td style="text-align:left;">任何一个十六进制数(即0-9 a-f A-F)</td>
<td colspan="4" style="text-align:center;">[:xdigit:]</td>
</tr>
</table>四、不同类型正则表达式比较
当使用BERs(基本正则表达式)时, 必须在下列这些符号前加上转义字符\屏蔽掉它们的 speical meaning ? + | { } ( )
修饰符用在正则表达式结尾, 例如:/dog/i, 其中 “i“ 就是修饰符, 它代表的含义就是:匹配时不区分大小写. 常见的修饰符如下:
- g 全局匹配(即:一行上的每个出现, 而不只是一行上的第一个出现)
- s 把整个匹配串当作一行处理
- m 多行匹配
- i 忽略大小写
- x 允许注释和空格的出现
- U 非贪婪匹配
五、正则表达式顺口溜
网上有流传的一套关于正则的口诀, 内容多却不够顺口, 我就编个顺口溜吧, 不够雅驯, 姑妄闻之.
正则匹配很重要 文本处理功能妙
基本规则要知道 字符次数范围到
字符匹配最简单 点把尖刀把山翻(.^$)
点号任意都能套 尖刀首尾来报告
特殊字符认不了 反斜线来把它找
若要重复字符串 小括号中站一站
次数限定要记好 星加问号少不了{*+?}
星号任意都能套 加号至少要一炮
剩下问号零或幺 不怕麻烦大括号
说起范围记得好 中括号中字符表[|^-]
竖杠两旁选一个 尖尖进去全完了
横线跑来帮帮忙 由低到高全阵亡
六、正则表达式图解
如果你想弄清楚某个正则表达式的意思, 可以试试regexper%5BAZ%5D%24).
虽然只支持javascript的正则语法, 对其他语言也很有帮助.
相关资料
- linux shell 正则表达式(BREs,EREs,PREs)差异比较
或
- Shell正则表达式与grep、sed、awk的特点
- Shell正则表达式
- Linux/Unix工具与正则表达式的POSIX规范
- 正则表达式口诀及教程
- 各种语言正则表达式语法比较
- 常用的正则表达式全面总结
- 揭开正则表达式的神秘面纱
- 正则图解