正则表达式
2014-11-16 00:00
411 查看
1. 综述
正则表达式(regular expression)通常简写为 regex 或 re,是一种指定字符串模式的简洁方式。图 20-1、20-2、20-3汇总了正则表达式的使用语法。
正则表达式是一种指定字符模式的简洁方式。在正则表达式中,普通字符匹配自身,特定的元字符拥有特殊的含义。本表列举了用来执行基本模式匹配的元字符。
在正则表达式中,下述元字符称为重复运算符,可以用来匹配多个指定字符的实例。
注意:一些程序不支持{,m},因为{,m}不是标准的。
正则表达式中可以包含有定义一组字符的字符类。为了方便起见,正则表达式中有一组预定义字符类,可以将这些预定义字符类用作字符集合的缩写。本表示范了最重要的预定义字符类。注意方括号和冒号都是名称的一部分。
最右边的一列给出了与预定义字符类等价的字符范围。如果系统使用的是 C 排序序列,则可以使用这些范围取代类的名称。为了确保系统使用的是 C 排序序列,可以将环境变量 LC_COLLATE 的值设置为 C。
2. 基本和扩展正则表达式
Unix支持两种主要的正则表达式变体:一个现代版本,一个以前的废弃版本。现代版本的正则表达式是扩展正则表达式(extended regular expression),或者简称为 ERE。它是当前的标准,疏于 IEEE 1003.2 标准(POSIX 的一部分)。以前版本的正则表达式是基本正则表达式(basic regular expression),或者简称为 BRE。因其功能弱,语法容易混淆,已废弃。但仍然有时候不得不选择使用基本正则表达式。(例如,sed 只支持 BRE)
使用扩展正则表达式:grep -E 或 egrep
图 20-4,列举了基本正则表达式的限制,供参考
3. 匹配单词和行
假定有一个文件 data,考虑以下用法:grep '^Harley' data
grep 'Harley$' data
grep '^Harley$' data
grep '^$' data | wc -l
grep '\<kn' data
grep 'ow\>' data
grep '\<know\>' data
下述3条命令都是等价的:
grep -w 'cat' data
grep '\<cat\>' data
grep '\bcat\b' data
4. 匹配字符:字符类
假定有一个文件 data,考虑以下用法:grep 'Har..y' data
grep 'H[aA]' data
grep 'li[cs]en[cs]e' data
grep '\<li[cs]en[cs]e\>' data
5. 预定义字符类:范围
有一些字符集是比较常见的,因此他们被冠以相应的名称,从而方便使用。这些字符集称为预定义字符类。预定义字符类的使用比较直接,除了一个规则之外,这个规则是:方括号实际上是名称的一部分。因为,当时用预定义字符类时,必须包含第二组方括号,以维持正确的语法(当使用字符类时,外面的方括号不属于类)。
grep '21[[:alpha:]]' data
grep '[[:upper:]][[:upper:]][[:digit:]][[:lower:]]' data
grep '[3-7]' data
grep 'X[0-9][0-9]' data grep 'X[[:digit:]][[:digit:]]' data
grep 'X[^ao]' data
grep '[^A-Za-z]' data
grep '[^[:alpha:]]' data
6. 区域设置和排序序列
此处不单独阐述。为了将字典排序序列改变成 C 排序序列,提示以下命令:export LC_COLLATE=C
export LC_COLLATE=POSIX
setenv LC_COLLATE C
setenv LC_COLLATE POSIX
locale
locale -a
7. 使用范围和预定义字符类
考虑以下命令:grep 'H[[:lower:]]' data
grep 'H[a-z]' data
grep '[A-Za-z][0-9][a-z]' data
grep '[[:alpha:]][[:digit:]][[:lower:]]' data
grep '[A-Z][0-9][A-Z] [0-9][A-Z][0-9]'
data grep '[[:upper:]][[:digit:]][[:upper:]] [[:digit:]][[: upper:]][[:digit:]]' data
选择使用哪一种类型的字符类——是范围还是预定义名称——由自己决定。许多以前的 Unix 用户倾向于使用范围,因为他们学习得就是范围。此外,范围还比名称更容易键入。
但是,名称更可读,从而使得它们更适合在 shell 脚本中使用。另外,不管使用哪一种区域设置或语言,名称总是正确的,因此它们的移植性更出色。例如,假设处理的文本中包含非英语字符,如 é(有重音符的 e)。通过使用 [:lower:],就可以确保获取 é。但是,如果使用a-z的话,可能实现不了这种效果。
8. 重复运算符
考虑以下命令:grep 'H[a-z]*' data
grep 'H[[:lower:]]*' data
grep 'error.*code' data
grep ':.*:' data
grep 'variable[0-9]+' data
grep 'variable[[:digit:]]+' data
grep '[vV]ariable[0-9]+' data
grep 'colou?r' data
grep '\<[0-9]{2,3}\>' data
grep 'cat|dog|bird|hamster' data
grep '\<(cat|dog|bird|hamster)\>' data
grep '\$' data
grep '\\\*.*[A-Za-z]+\$' data
10. 解决3个有趣的难题
字典文件常见位置:/usr/share/dict/words
/usr/dict/words
/usr/share/lib/dict/words
1. 哪些英语单词以“qu”开头并以“y”结尾?
grep '^qu[a-z]+y$' /usr/share/dict/words
2. 查找一个包含所有 5 个元音字母 a、e、i、o、u(并且以该顺序出现)的普通英语单词。这 5 个字母不必连在一起,但是它们必须按字母表顺序出现。
grep 'a[a-z]*e[a-z]*i[a-z]*o[a-z]*u' /usr/share/dict/words
3. 查找所有两个字母长的 Unix 命令
ls /bin | grep '^[a-z]{2}$'
ls /bin | egrep '^[a-z]{2}$'
ls /bin | grep '^[a-z][a-z]$'
ls /usr/bin | grep '^[a-z]{2}$'
ls /bin | grep -c '^[a-z]{2}$'
ls /usr/bin | grep -c '^[a-z]{2}$'
附录1. 通配符
每当键入以文件名作为参数的命令时,可以通过使用特定的元字符——通配符(wildcard)——指定多个文件名。元字符是由shell 解释时拥有特殊含义的字符。当在文件名中使用通配符时,通配符就拥有特殊的含义。乍一看,通配符和正则表达式元字符及其相似。实际上,通配符更加简单一些。此外,它们只有一个用途:当键入一条命令时匹配一组文件名。
图 24-5 列出了基本的通配符及其含义。注意:当键入路径名时,不能匹配 / 字符,该字符必须显示键入。
根据所使用的 shell 的类型不同,使用通配符指定文件的正式称呼也有所不同。在 Bash 中,称之为路径名扩展(pathname expansion);在 Korn shell 中,称之为文件名生成(filename generation);在 C-Shell 或 Tcsh 中,称之为文件名替换(filename substitution)。当 shell 执行实际替换时,称之为通配(globbing)
通配符可以使用范围匹配指定字符集中的字符。最常见的包括 [a-z] 匹配小写字母,[A-Z] 匹配大写字母。这类范围适用于 C 区域设置,而不适用于 en-US 区域设置。作为备选方法,可以使用预定义字符类替代范围。图 24-6 中列举了一些最重要的预定义字符类。
一些例子:
ls h*
ls /bin/[a-z][a-z] /usr/bin/[a-z][a-z]
ls /bin/[[:lower:]][[:lower:]] /usr/bin/[[:lower:]][[:lower:]]
ls /home/{harley,weedly,tln}
cat olddata1 olddata2 olddata3 newdata1 newdata2 newdata3 > master
cat {old,new}data{1,2,3} > master
cat {old,new}data[1-3] > master
mkdir ~/work/essays ~/work/photos ~/work/bin ~/work/music
mkdir ~/work/{essays,photos,bin,music}
touch data{old,new,backup,master,final}
正如前面所述,当 shell 匹配通配符时,在参数传递给程序之前,通配符已变成实际文件名。如果使用的模式不匹配任何文件,那么 shell 将显示一个适当的消息。
附录2. grep 重要的选项
以下是一些例子:ls -F /etc | grep -c "/"
grep -i pizza food-costs
grep -in pizza food-costs
grep -l Harley names oldnames newnames
grep -L Harley names oldnames newnames
grep -w now memo
grep -v DONE homework
grep -cv DONE homework
grep -x Harley names
grep -r initialize admin
grep -rs / 'shutdown now'
附录3. 补充
\s:匹配任意的空白符\S:匹配任意不是空白符的字符