POSIX正则表达式

POSIX定义正则表达式两个标准:BRE(基本re)和ERE(扩展re)
区别较少:ERE加入少量新功能,取消了在BRE中的后向引用。

首先需要了解,各程序支持正则表达式情况:
(其中第三行<>为匹配单词开头结尾)

Is support grep sed ed ex/vi more egrep awk lex
BRE y y(default) y y y - - -
ERE - y - - - y y y
< .. \> y y y y y - - -

RE基础操作meta字符

BRE和ERE通用

字 符 功能
\ 转义
. 匹配任意字符
* 重复0~INF次
^ $ 匹配紧接着的正则表达式,在行或者字符串的起始(末尾)处。对于BRE而言,仅在开头(末尾)有效。对于ERE而言,任何位置都有效
[..] 匹配方括号里面任意字符,例如A-Z,方括号里面还可以有字符集,例如[:alpha:]

BRE专用

字 符 功能
\{a,b\} 区间表达,意思重复a~b次,若{a,},表示至少a次,若{a}则重复a次
\(..\) 将括号范围存储在“保留空间”,供后序引用
\n 转义的后序引用,例如\1引用前面的第一条括号的表达式

ERE专用

字 符 功能
{a,b} 重复a~b次,与BRE功能一致,少了\
(..) 正则表达式群,与BRE类似
? 重复0~INF次
+ 重复1~INF次
\w 匹配任何单词组成,若\W则是非单词
\d 匹配数字,若\D非数字
\b 匹配单词起始和或结尾的空字符串,在awk中用\y表示
\B 匹配单词之间的空字符串
\<..\> 匹配单词起始和结尾
管道符(竖线) 分隔多个正则表达式

POSIX字符集

使用时候,注意再外层套一个方括号:

sed 's;[[:alnum:]];####;g' 1.txt   #所有字符替换成井号

如下表:

字符 功能 字符 功能
[:alnum:] 字母加数字 [:digit:] 数字
[:alpha:] 字母 [:lower:] 小写字母
[:blank:] 空格/tab [:space:] 空白字符
[:cntrl:] 控制字符 [:graph:] 非空格字符
[:print:] 可显示的字符 [:punct:] 标点符号
[:upper:] 大写字符 [:xdigit:] 十六进制数字

RE运算优先级(由高到低)

BRE专用

运算 表示意义
[. .] [==] [::] 字符排序的方括号
\xxxx 转义meta字符
[ ] 方括号表达式
\( \) \digit 子表达式,后向引用
* \{a,b\} 重复次数表达式
无符号 连续
^ $ 锚点

ERE专用
与BRE大致相同,增加几个而已

运算 表示意义
[. .] [==] [::] 字符排序的方括号
\xxxx 转义meta字符
[ ] 方括号表达式
( ) \digit 子表达式
* + ? {a,b} 重复次数表达式
无符号 连续
^ $ 锚点
管道符 分隔多个正则表达式

其他

匹配任意字符 包括换行符

众所周知 .* 是匹配任意字符,不包括换行符,如果想跨行搜索,就很难进行匹配了,使用以下任意一种表达式进行匹配包括换行符。

([\w\W]*)
([\s\S]*)
([\d\D]*)

But I found it works well on gedit, while terribly on sed.

类似的使用方法:
这个表达式可以匹配所有的英文:

[ -~]

这个表达式可以匹配所有的非英文(比如中文)

[^ -~]

非常巧妙!参考链接:点击这里

字符

符号 功能
\s 空白,\S为非空格
\t tab
\r 回车,同理\n是换行
\e escape
\Oxx 八进制xx的字符
\Xxx 十六进制为xx的字符
\uxxxx Unicode
\A 字符串开头,不受处理多行选项的影响,同理\Z为结尾

小括号特定用途

1.捕获

符号 功能
(? < name > expression) 匹配表达式,并捕获到名称为name的组里
(?:exp) 匹配表达式,不捕获匹配的文本,也不给其分组分配组号

2.零宽断言

符号 功能
(?=expression) 匹配表达式前面的位置
(?<=expression) 匹配表达式后面的位置
(?<!expression) 匹配前面不是表达式的位置
(?!expression) 匹配后面不是表达式的位置

接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。

前两种断言:正预测先行断言

  • (?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc。
  • (?<=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。
  • 假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?<=\d)\d{3})*\b,用它对1234567890进行查找时结果是234567890。
  • 这个例子同时使用了这两种断言:(?<=\s)\d+(?=\s)匹配以空白符间隔的数字(再次强调,不包括这些空白符)。

后两钟断言:负向零宽断言

  • 前面我们提到过怎么查找不是某个字符或不在某个字符类里的字符的方法(反义)。但是如果我们只是想要确保某个字符没有出现,但并不想去匹配它时怎么办?例如,如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样:
  • \b\wq[^u]\w\b匹配包含后面不是字母u的字母q的单词。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为[^u]总要匹配一个字符,所以如果q是单词的最后一个字符的话,后面的[^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的\w\b将会匹配下一个单词,于是\b\wq[^u]\w*\b就能匹配整个Iraq fighting。
  • 负向零宽断言能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:\b\wq(?!u)\w\b。
  • 零宽度负预测先行断言(?!exp),断言此位置的后面不能匹配表达式exp。例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。
  • 同理,我们可以用(?<!exp),零宽度正回顾后发断言来断言此位置的前面不能匹配表达式exp:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。

3.注释
使用(?#comment),例如:

2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)。

搜索中文

貌似与英文不太一样,占用两个字节的编码,需要重复几次。
比如搜索:

第[一二三]+章

要加上一个加号,否则搜不到结果。