现在的位置: 首页 > 综合 > 正文

正则表达式解惑

2013年10月31日 ⁄ 综合 ⁄ 共 3233字 ⁄ 字号 评论关闭

     正则表达式是一种字串表达的方式,可用以指定具有某特征的所有字串。在 linux 里,正则表达式被应用得非常广泛,但是不同的工具中使用方法略有不同。本文主要来看下面几种容易混淆的情况。

一、Linux中正则表达式的基本知识

1、了解组成基本正则表达式的元素。

字符 意义和用法
点号(.) 任意字符
斜线(\)  表示转意字符,比如点号,如果真的需要匹配点号本身,则需要用 "\." 来表示
小尖号(^) 行首定位符,表示行首或否定,比如 "^48" ,即匹配以"48"开头的字符串,如"48 1 3 ..." ;若放在方括号内,比如"^[^48]",匹配不以"4"或"8"开头的任何字符串,如"1234"
Dollar符($) 行尾定位符,表示行尾,比如 "48$" ,即匹配以"48"结尾的字符串,如 "... 12 34 8 48"
星号(*) 表示前面的字符重复0~N,比如
"8*" ,即匹配包含若干个8的字符串,如 "... 484..." 或者 "...5888.."等
方括号([...]) 表示匹配方括号列表中的任一个,比如"[0-9a-z]",即匹配任何单个数字或字母,比如 "a" 或者 "1" ,注意区别 "[0-9][a-z]" ,它表示第一个是数字,接下来的字符是字母!
大括号(\{m\}) 表示前面的字符重复m次,比如"8\{2\}",即匹配包含"88"的字符串,比如"...1288.."等。另外 \{m,\}表示至少m次 ;\{m,n\}表示至少m次,不超过n次。
转意左尖括号(\<) 词首定位符,表示匹配该词首的行,比如"\<92" ,即匹配行中包含以"92"开头的词,如"ab xy 92d aa" 和"9 d 92"
转意右尖括号(\>) 词尾定位符,和上面的相反,表示匹配该词尾的行










2、扩展的正则表达式的元素。

字符  意义和用法
加号(+) 表示重复前面的字符1~N次。例子嘛,类比上面的。
问号(?) 表示重复前面的字符0或1次。也就是该字符最多出现1次。
竖线(|) 用 or 的方式匹配多个字符串(注意,不是单个字符)。比如 "12|34",也就是匹配包含了"12" 或 "34"的字符串
括号((...)) 表示字符组。比如"(12)+",意思是字符串中至少包含一个"12",比如 "...13124..." 或者 "...1212124..."。





[注意] 

1) 对于正则表达式本身而言,所有字符,如 . * ^ $ [ ] + ? | ( ) { } 都是带有特定含义的! 若要使用其本意,得加上转意符。
2) 在Linux各种工具如grep、awk中使用正则表达式,有细微的不同!详情见下面的解释。
3) 有四种元字符  \{ ,\}, \<, \>  各流派和工具对其支持程度不一!!使用时需格外注意!


二、find 命令

在 find 命令中,常见的用法如下,一般搜索文件名可以使用下面的命令:

find [path] -name [pattern] -print
比如:
find . -name "[a-z][0-9].txt" -print

这里的pattern(算不上是正则表达式)中特殊字符的含义如下:

*    文件名中的任意字符(与上面的说明有很大不同,和 shell 的用法差不多,表示 wild card)
?  文件名中的任意单个字符
[...]  匹配方括号内的任一字符
[!...]  不匹配方括号内的任一字符

[小结] 这里的 pattern 需要用引号引起来,避免误以为是shell 命令。

显然,这种用法是很局限的,但是通过加入正则表达式后就不一样了。用法如下:

find . -regex ".*\.\(txt\|sh\)"

使用 "-regex" 选项来表明 find 命令后面匹配的是正则表达式,用法上少许有些不同。

[解释] find 是在查找当前目录下以 .txt 和 .sh 结尾的文件;如果用 "-iregex" 表示忽略大小写。

[注意] 用 " -regex " 选项时,正则表达式中的所有特殊字符都需要转意!比如 "()" "|" "{}" 等。一般使用正则表达式时 "|"  "(...)" 等是不需要转意的!

[其他]

如果觉得转移麻烦,也可以选择 "-regextype posix-egrep " 选项来扩展,比如:

find . -regextype posix-egrep  -regex ".*\.(txt|sh)"

如 "(...)" "{...}" 是不转意的! 这点上是和上面的规则稍有不同的!


二、grep 命令

grep 命令的常见使用方式如下:

grep [其他选项] '要搜索的字符串' 文件
比如:
$ ls
arr.dat  avg.txt  data  data.f  emp.data  ip.sh  loop.sh  pwd  select_sort.sh
$ ls | grep '^i.*\.sh' 
ip.sh

[解释]  grep命令的意思是查找当前目录下以字母"i"开头,以".sh"结尾的文件名。grep 有很多有用的选项,比如 "-n" "-v" "-i" 等。值得注意的是正则表达式要用单引号引起!

[其他]  如果希望使用扩展的regexp,则需要加上"-E" 选项。

比如:

grep -E '(219|216)+p' data.f

意思是查找类似于 "219pp" 之类的字符串。其中表示或关系的"|" 或 "+" 都是扩展正则表达式的内容!

[注意]:

grep命令中,仅 . * ^ $ [ ] 有特殊含义,若想使用其本意,则需转意!比如 '\*' 等!其他字符如? + |
{ } ( ) 代表本意,若想使用其特殊含义,则需转意!

grep -E 命令中,字符 . * ? + ^ $ [ ] | ( ) 都有特殊含义,如想使用本意,则需转意! 仅{ } 代表本意! 若想使用其特殊含义,则需转意!(有的工具不支持{})

例如:

grep -E '(219|216)+p' data.f
grep '\(219\|216\)\+p' data.f 

可以参考 man grep 中的内容,摘抄如下:

Basic vs Extended Regular Expressions
In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead use the backslashed versions \?, \+, \{, \|, \(,and \).

Traditional egrep did not support the { meta-character, and some egrep implementations support \{ instead, so portable scripts should avoid { in grep -E patterns and should use [{] to match a literal {.

GNU grep -E attempts to support traditional usage by assuming that { is not special if it would be the start of an invalid interval specification. For example, the command grep -E '{1' searches for the two-character string {1 instead of reporting a syntax error
in the regular expression. POSIX.2 allows this behavior as an extension, but portable scripts should avoid it.


三、awk命令

awk 命令的常见用法如下:

awk '$1~/^123+\.txt/ { print $0 }' data.f

awk 中匹配(用"~")或者不匹配("!~") 一个正则表达式(必须放在"/..../"里)。上例的意思是 匹配字符串第一列满足 "以12开头,接着有至少一个'3',以'.txt'结尾的字符串 ",比如 "123333.txt"之类的。

[注意]:

awk 中的正则表达式,字符 . * ? + ^ $ [ ] | ( ) 都有特殊含义,若想代表其本意,则需转意。特别注意的是awk
中不支持字符
{...} 的特殊含义!


小结:特别注意转意字符的用法,什么时候要转意,什么时候不需要转意!

(全文完)

抱歉!评论已关闭.