【计理01组06号】正则表达式基础入门

  • A+
所属分类:linux技术
摘要

正则表达式(Regular Expression)是一个定义搜索模式的字符序列。 在做文字处理或编写程序时,若需要用到查找、替换等功能时,可以使用正则表达式来简单便捷地完成目标。

正则表达式介绍与基础

正则表达式(Regular Expression)是一个定义搜索模式的字符序列。

在做文字处理或编写程序时,若需要用到查找、替换等功能时,可以使用正则表达式来简单便捷地完成目标。

简单而言,正则表达式通过使用一些特殊符号,使得使用者可以方便轻松地实现查找、删除、替换等功能。

Vi 中经常会使用到正则表达式,为了充分发挥 shell 编程的威力,Linux 使用者需要精通正则表达式。

首先是正则表达式的特殊符号:

[:alnum:]代表英文大小写字母及数字 [:alpha:]代表英文大小写字母 [:blank:]代表空格和 tab 键 [:cntrl:]键盘上的控制按键,如 CR,LF,TAB,DEL [:digit:]代表数字 [:graph:]代表空白字符以外的其他 [:lower:]小写字母 [:print:]可以被打印出来的任何字符 [:punct:]代表标点符号 [:upper:]代表大写字母 [:space:]任何会产生空白的字符如空格,tab,CR 等 [:xdigit:]代表 16 进位的数字类型

特殊符号实例

在 WebIDE 中使用 touch 命令或图形界面新建一个 .txt 文件并将下文中的文本内容复制进去。

touch regular_express.txt

也可以使用 wget 指令从本节开头的实验环境说明处下载,这两种方式取得的文件是一样的。

文本内容为:

"Open Source" is a good mechanism to develop programs. apple is my favorite food. Football game is not use feet only. this dress doesn't fit me. However, this dress is about $ 3183 dollars. GNU is free air not free beer. Her hair is very beauty. I can't finish the test. Oh! The soup taste good. motorcycle is cheap than car. This window is clear. the symbol '*' is represented as start. Oh!My god! The gd software is a library for drafting programs. You are the best is mean you are the no. 1. The world <Happy> is the same with "glad". I like dog. google is the best tools for search keyword. goooooogle yes! go! go! Let's go. # I am VBird

【计理01组06号】正则表达式基础入门

使用特殊符号查找小写字母:

grep -n '[[:lower:]]' regular_express.txt

红色为匹配成功的字符。

【计理01组06号】正则表达式基础入门

使用特殊符号查找数字:

grep -n '[[:digit:]]' regular_express.txt

【计理01组06号】正则表达式基础入门

grep命令与正则表达式

查找特定字符串

参数说明:

  • -a :以 text 档案的方式搜寻 binary 档案数据
  • -c :计算找到 '搜寻字符串' 的次数
  • -i :忽略大小写的不同,所以大小写视为相同
  • -n :顺便输出行号
  • -v :反向选择,亦即显示没有 '搜寻字符串' 内容的行

grep -n 'the' regular_express.txt grep -in 'the' regular_express.txt

【计理01组06号】正则表达式基础入门

反向查找,当该行没有字符串'the'时才显示在屏幕上。

grep -vn 'the' regular_express.txt

【计理01组06号】正则表达式基础入门

字符组匹配

[ ] 可以用来查找字符组。

值得注意的是,无论 [ ] 中包含多少个字符,它都只代表一个字符。比如说,我们想要查找 tast 或者 test 这两个字符串,注意到二者的拼写大部分相同,都是 t?st 的形式,故此时可以使用 [ ] 进行查找:

grep -n 't[ae]st' regular_express.txt

【计理01组06号】正则表达式基础入门

字符组支持使用连字符 - 来表示一个范围。当 - 前后构成范围时,要求前面字符的码位小于后面字符的码位。

[^] 为反向选择字符组,用于排除后面的字符,使用方式为 [^...]

需要注意 [^] 与参数 -v 的区别,尽管二者都表示反向选择,但是如果包含有反向选择的字符的行含有其他字符的话,[^] 仍会输出该行,而 -v 则只会输出不含有反向选择的字符的行。

下面给出一些应用示例:

[abc] :表示 “a” 或 “b” 或 “c” [0-9] :表示 0~9 中任意一个数字,等价于 [0123456789] [u4e00-u9fa5] :表示任意一个汉字 [^a1<] :表示除 “a”、“1”、“<” 外的其它任意一个字符 [^a-z] :表示除小写字母外的任意一个字符

使用 - [^] 查找 Xoo 形式的字符串,要求 oo 之前不能包含小写字母:

grep -n '[^a-z]oo' regular_express.txt

回忆前一节所提到的正则表达式特殊符号,[:lower:] 表示小写字母,因此也可以使用

grep -n '[^[:lower:]]oo' regular_express.txt

【计理01组06号】正则表达式基础入门

这两者是等价的,但是可以看出,使用[a-z]来表示小写字母明显更加便捷,也更加灵活。

查找字符 oog

grep -n 'oog' regular_express.txt

如果我不想要 oog 字符前面有 g,则使用 [^g]oog

grep -n '[^g]oog' regular_express.txt

同理,若不想让字符 oog 前面为 g 或者 o,则使用 [^go]oog

grep -n '[^go]oog' regular_express.txt

【计理01组06号】正则表达式基础入门

其中

grep -n '[^go]oog' regular_express.txt

返回结果为空,表示没有匹配到符合要求的字符串。

行首符 ^ 与行尾符 $

在第一个实验中,我们使用

grep -n 'the' regular_express.txt

查找含有 the 的字符串,如果你只想查找行首为 the 的字符行,则使用以下命令:

grep -n '^the' regular_express.txt

查找行首为大写字母的所有行:

grep -n '^[A-Z]' regular_express.txt

注意行首符 ^ 和反向选择 [^] 的区别,^[A-Z] 表示以大写字母开头。[^A-Z] 表示除了大写字母 A-Z 的所有字符。

行尾符 $ 的用法与行首符类似。

查找以字母 d 结尾的行:

grep -n 'd$' regular_express.txt

这里有一个小技巧,将行首符与行尾符连用,可以用来查找空行:

grep -n '^$' regular_express.txt

应用实例

查看 /etc/insserv.conf 文档

^$: 过滤掉空白行

^#: 过滤掉注释行(以 # 号开头)

cat -n /etc/insserv.conf grep -v '^$' /etc/insserv.conf | grep -v '^#'

【计理01组06号】正则表达式基础入门

任意一个字符 . 与重复字符 *

查找 a?ou? 类型的字符:

grep -n 'a.ou.' regular_express.txt

其中小数点表示任意一个字符,一个小数点只能表示一个未知字符。

*(星号):代表重复前面 0 个或者多个字符。 e*: 表示具有空字符或者一个以上 e 字符。 ee*,表示前面的第一个 e 字符必须存在。第二个 e 则可以是 0 个或者多个 e 字符。 eee*,表示前面两个 e 字符必须存在。第三个 e 则可以是 0 个或者多个 e 字符。 ee*e :表示前面的第一个与第三个 e 字符必须存在。第二个 e 则可以是 0 个或者多个 e 字符。

下面的第一条命令与第二条命令由于允许存在空字符,所以会打印所有文本。

grep -n 'e*' regular_express.txt grep -n '@*' regular_express.txt grep -n 'eee*' regular_express.txt

限定连续字符范围 { }

{ } 可限制一个范围区间内的重复字符数。如果现在要求找出存在连续的两个 o 字符的字符串,根据前面所学的知识,我们可以使用:

grep -n 'ooo*' regular_express.txt

另一种方式是使用 { }。由于 { } 在 shell 中有特殊意义,故在使用时需要用到转义字符

查找连续的两个 o 字符:

grep -n 'o{2}' regular_express.txt

查找 g 后面接 2 到 5 个 o,然后再接 g 的字符串:

grep -n 'go{2,5}g' regular_express.txt

总结:

^word 表示待搜寻的字符串(word)在行首 word$ 表示待搜寻的字符串(word)在行尾 .(小数点) 表示 1 个任意字符 表示转义字符,在特殊字符前加 会将特殊字符意义去除 * 表示重复 0 到无穷多个前一个 RE(正则表达式)字符 [list] 表示搜索含有 l,i,s,t 任意字符的字符串 [n1-n2] 表示搜索指定的字符串范围,例如 [0-9] [a-z] [A-Z] 等 [^list] 表示反向字符串的范围,例如 [^0-9] 表示非数字字符,[^A-Z] 表示非大写字符范围 {n,m} 表示找出 n 到 m 个前一个 RE 字符 {n,} 表示 n 个以上的前一个 RE 字符

sed命令与正则表达式

sed 是非交互式的编辑器。它不会修改文件,除非使用 shell 重定向来保存结果。默认情况下,所有的输出行都会被打印到屏幕上。

sed 编辑器逐行处理文件(或输入),并将结果打印到屏幕上。

具体过程如下:首先 sed 把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后处理临时缓冲区中的行,完成后把该行发送到屏幕上。

sed 每处理完一行就将其从临时缓冲区删除,然后将下一行读入,进行处理和显示。处理完输入文件的最后一行后,sed 便结束运行。sed 把每一行都存在临时缓冲区中,对这个副本进行编辑,所以直接使用不会修改原文件内容。

如果要修改原文件,需要添加 -i 选项。

输出文件内容

将 regular_express.txt 的内容列出并打印行号,并将 2-5 行删除显示:

nl regular_express.txt | sed '2,5d'

2,5d 表示删除 2~5 行,d 即为 delete。

【计理01组06号】正则表达式基础入门

同理,删除第 2 行:

nl regular_express.txt | sed '2d'

删除第三行到最后一行, $ 表示定位到最后一行:

nl regular_express.txt | sed '3,$d'

使用 -i 在原文件中删除第 1 行:(注意:该指令会修改原文件)

sed -i '1d' regular_express.txt

使用 a 和 i 新增输出

在第二行后添加字符串 test:

nl regular_express.txt | sed '2a test'

在第二行前添加字符串 test:

nl regular_express.txt | sed '2i test'

在第二行后添加两行 test,n 表示换行符:

nl regular_express.txt | sed '2a testntest'

行内容替换

将 2-5 行的内容替换为 No 2-5 number,c 为替换内容选项:

nl regular_express.txt | sed '2,5c No 2-5 number'

【计理01组06号】正则表达式基础入门

输出指定行

输出 regular_express.txt 的第 5-7 行,其中 -n 为安静模式选项,我们在前面的章节中已经介绍过。

执行以下两条命令可以明显看出区别:

nl regular_express.txt |sed -n '5,7p' nl regular_express.txt |sed '5,7p'

【计理01组06号】正则表达式基础入门

字符串替换

格式为:sed 's/lodstr/newstr/g'

来看一个实例。首先查看本机 IP 地址:

ifconfig eth0

字段inet 地址:192.168.x.x即为本机的 IP 地址,这是经由 NAT 转换后分配的内网 IP 地址,在此不做展开。

之后使用 grep 指令在 ifconfig eth0 的结果中查找 inet,并打印至终端:

ifconfig eth0 | grep 'inet'

可以使用字符串替换功能将 IP 前面的部分予以删除,按照思路,也就是将 inet 地址: 替换为空字符串,可以简单写成:

ifconfig eth0 | grep 'inet '| sed 's/inet 地址://g'

(注意中文字符不能直接复制,需要自己在终端输入)

但正则表达式在实际应用中可以非常灵活,回想一下我们在前两节所学的关于正则表达式的知识(忘了也不要紧,可以随时返回查看)。

. 表示任意一个字符,* 表示重复字符,{ } 表示限定连续字符范围,所以正则表达式也可以写成:

ifconfig eth0 |grep 'inet '| sed 's/.inet...://g' # 或者 ifconfig eth0 |grep 'inet '| sed 's/.{0,9}://'

表达式的写法并不唯一,在此也并未全部列出,大家亦可自行尝试使用其他写法,欢迎在评论区中讨论。

将 IP 后面的部分删除:

/sbin/ifconfig eth0 |grep 'inet '| sed 's/.inet...://g'| sed 's/..:.*$//g' /sbin/ifconfig eth0 |grep 'inet '| sed 's/.inet...://g'| sed 's/.{0,3}:.*$//g'

【计理01组06号】正则表达式基础入门

上述指令是比较复杂的正则表达式运用,熟悉正则表达式后可以明显地简化指令,简单便捷地完成文件的查询、修改等任务。

正则表达式扩展应用

使用扩展正则表达式 egrep

首先来看一条前面章节学习过的用来去除空白行和注释行的指令:

grep -v '^$' regular_express.txt |grep -v '^#'

可见,通常的 grep 指令需要使用两次管线命令。那么如果使用扩展正则表达式,则可以简化为:

egrep -v '^$|^#' regular_express.txt

利用支持扩展正则表达式的 egrep 与特殊字符 | 的组合功能来间隔两组字符串,如此一来,可以极大地化简指令。

此外,也可以使用 grep -E 来使用扩展正则表达式,不过一般更建议直接使用 egrepgrep -Eegrep 之间类似命令别名的关系。

扩展规则(一)

回忆一下,在非扩展正则表达式中,我们使用 * 来表示任意个重复字符(零至无穷多个):

grep -n 'goo*d' regular_express.txt

在扩展正则表达式中,则可以进一步细分为一个或一个以上零个或一个字符:

+ 表示重复一个或一个以上的前一个字符

egrep -n 'go+d' regular_express.txt

? 表示重复零个或一个的前一个字符

egrep -n 'go?d' regular_express.txt

执行上述三条指令,比较三者的不同。

【计理01组06号】正则表达式基础入门

扩展规则(二)

| 表示用或(or)的方式找出数个字符串

查找 gd 或 good:

egrep -n 'gd|good' regular_express.txt

() 表示找出组字符串

查找 glad 或 good,注意到由于二者存在重复字母,所以可以将其合并:

egrep -n 'g(la|oo)d' regular_express.txt

【计理01组06号】正则表达式基础入门

()+ 多个重复群组判别

查找开头是 A 结尾是 C 中间有一个以上的 xyz xz 字符串:

echo 'AxyzxyzxyzxyzC'|egrep 'A(xyz)+C' echo 'AxyzxyzxyzxyzC'|egrep 'A(xz)+C'

结果显示 A(xyz)+C 可以匹配,A(xz)+C 没有匹配项。

【计理01组06号】正则表达式基础入门