正则表达式与文件格式化处理(1)-基础正则表达式练习(主)
基础正则表达式
正则表达式定义
简单的说,正则表达式就是处理字串的方法,他是以行为单位来进行字串的处理行为,
正则表达式通过一些特殊符号的辅助,可以让使用者轻易的达到搜寻
,删除
,取代
某特定字串的处理程序!
正则表达式的广泛用途
- 系统管理员管理主机
- 邮件服务器过滤垃圾邮件
延伸的正则表达式
正则表达式的字串表示方式依照不同的严谨度而分为: 基础正则表达式
与延伸正则表达式
语系对正则表达式的影响
为什么语系的数据会影响到正则表达式的输出结果呢?我们在第零章计算机概论的文字编码系统里面谈到,
文件其实记录的仅有 0 与1 ,我们看到的字符文字与数字都是通过编码表转换来的。
由于不同语系的编码数据并不相同,所以就会造成数据撷取结果的差异了。
举例来说,在英文大小写的编码顺序中, zh_TW.big5 及 C 这两种语系的输出结果分别如下:
- LANG=C 时: 0 1 2 3 4 ... A B C D ... Z a b c d ...z
- LANG=zh_TW 时: 0 1 2 3 4 ... a A b B c C d D ... z Z
上面的顺序是编码的顺序,我们可以很清楚的发现这两种语系明显就是不一样!
如果你想要撷取大写字符而使用 [A-Z] 时, 会发现LANG=C 确实可以仅捉到大写字符 (因为是连续的) ,
但是如果 LANG=zh_TW.big5 时,就会发现到, 连同小写的 b-z 也会被撷取出来!
因为就编码的顺序来看, big5 语系可以撷取到 “ A b B c C ... z Z ” 这一堆字符哩!
所以,使用正则表达式时,需要特别留意当时环境的语系
为何, 否则可能会发现与别人不相同的撷取结果喔!
由于一般我们在练习正则表达式时,使用的是相容于 POSIX 的标准,
因此就使用 “ C ” 这个语系! 因此,下面的很多练习都是使用 “LANG=C ” 这个语系数据来进行的喔!
特殊符号代表意义
另外,为了要避免这样编码所造成的英文与数字的撷取问题,因此有些特殊的符号我们得要了解一下
的! 这些符号主要有下面这些意义:
特殊符号 | 代表意义 |
---|---|
[:alnum:] | 代表英文大小写字符及数字,亦即 0-9, A-Z, a-z |
[:alpha:] | 代表任何英文大小写字符,亦即 A-Z, a-z |
[:blank:] | 代表空白键与 [Tab] 按键两者 |
[:cntrl:] | 代表键盘上面的控制按键,亦即包括 CR, LF, Tab, Del.. 等等 |
[:digit:] | 代表数字而已,亦即 0-9 |
[:graph:] | 除了空白字符 (空白键与 [Tab] 按键) 外的其他所有按键 |
[:lower:] | 代表小写字符,亦即 a-z |
[:print:] | 代表任何可以被打印出来的字符 |
[:punct:] | 代表标点符号 ( punctuation symbol ),亦即: " ' ? ! ; : # $... |
[:upper:] | 代表大写字符,亦即 A-Z |
[:space:] | 任何会产生空白的字符,包括空白键 , [Tab], CR 等等 |
[:xdigit:] | 代表 16 进位的数字类型,因此包括: 0-9, A-F, a-f 的数字与字符 |
基础正则表达式练习
大前提是
- 语系已经使用 “ export LANG=C; export LC_ALL=C ” 的设置值;
- grep 已经使用 alias 设置成为 “ grep --color=auto ”
练习用的文件 regular_express.txt 获取命令:
wget http://linux.vbird.org/linux_basic/0330regularex/regular_express.txt
grep
在数据中查寻一个字串时,是以 整行
为单位来进行数据的撷取的!
搜寻特定字串
从文件 regular_express.txt 当中取得 the
这个特定字串
grep -n 'the' regular_express.txt
反向选择
呢?也就是说,当该行没有 the
这个字串时才显示在屏幕上
grep -vn 'the' regular_express.txt
从文件 regular_express.txt 当中取得 the
这个特定字串, 不论大小写
grep -in 'the' regular_express.txt
利用中括号 []
来搜寻集合字符
其实 []
里面不论有几个字符,他都仅代表某 一个
字符
如果我想要搜寻 test 或 taste 这两个单字时,可以发现到,其实她们有共通的 't?st' 存在~这个时候,我可以这样来搜寻:
grep -n 't[ae]st' regular_express.txt
而如果想要搜寻到有 oo 的字符时,则使用:
grep -n 'oo' regular_express.txt
但是,如果我不想要 oo 前面有 g 的话呢?此时,可以利用在集合字符的反向选择 [^] 来达成:
grep -n '[^g]oo' regular_express.txt
再来,假设我 oo 前面不想要有小写字符,所以,我可以这样写 [^abcd....z]oo , 但是这样似乎不怎么方便,由于小写字符的 ASCII 上编码的顺序是连续的, 因此,我们可以将之简化为下面这样:
grep -n '[^a-z]oo' regular_express.txt
也就是说,当我们在一组集合字符中,如果该字符组是连续的,例如大写英文 / 小写英文 / 数字等等,
就可以使用 [a-z]
,[A-Z]
,[0-9]
等方式来书写,那么如果我们的要求字串是数字与英文呢?
呵呵!就将他全部写在一起,变成: [a-zA-Z0-9]
。例如,我们要取得有数字
的那一行,就这样:
grep -n '[0-9]' regular_express.txt
但由于考虑到语系对于编码顺序的影响,因此除了连续编码使用减号 “ - ” 之外, 你也可以使用如下的方法来取得前面两个测试的结果:
那个 [:lower:]
代表的就是 a-z
的意思!请参考前面的说明表格
grep -n '[^[:lower:]]oo' regular_express.txt
只要取得有数字
的那一行,也可以写成这样:
grep -n '[[:digit:]]' regular_express.txt
行首与行尾字符 ^
$
查询一行字串里面有 the
的,那如果我想要让 the
只在行首列出呢? 这个时候就得要使用定位字符了!我们
可以这样做:
grep -n '^the' regular_express.txt
如果我想要开头是小写字符的那一行就列出呢?可以这样:
grep -n '^[a-z]' regular_express.txt
上面的指令也可以用如下的方式来取代的:
grep -n '^[[:lower:]]' regular_express.txt
好!那如果我不想要开头是英文字母,则可以是这样:
grep -n '^[^a-zA-Z]' regular_express.txt
指令也可以是:
grep -n '^[^[:alpha:]]' regular_express.txt
注意到了吧?那个 ^ 符号,在字符集合符号(括号 [] )之内
与之外
是不同的! 在 [] 之内
代表 反向选择
,在 [] 之外
则代表定位在行首
的意
义!
反过来思考,那如果我想要找出来,行尾结束为小数点 .
的那一行,该如何处理:
grep -n '\.$' regular_express.txt
特别注意到,因为小数点具有其他意义(下面会介绍),所以必须要使用跳脱字符 \
来加以解除其特殊意义!
如果我想要找出来,哪一行是 空白行
, 也就是说,该行并没有输入任何数
据,该如何搜寻?
grep -n '^$' regular_express.txt
Centos7 下我们以 /etc/rsyslog.conf 这个文件来作范例,你可以自行参考一下输出的结果
cat -n /etc/rsyslog.conf
在 CentOS 7 中,结果可以发现有 91 行的输出,很多空白行与 # 开头的注解行
grep -v '^$' /etc/rsyslog.conf | grep -v '^#'
- 结果少了很多行,其中第一个
-v '^$'
代表“不要空白行 - 第二个
-v '^#'
代表“不要开头是 # 的那行”喔!
任意一个字符 .
与重复字符 *
我们知道 万用字符 *
可以用来代表任意( 0 或多个)字符, 但是 正则表达式并不是万用字符
,两者之间是不相同
的! 至于正则表达式当中的 .
则代表 绝对有一个任意字符
的意思!这两个符号在正则表达式的意义如下:
.
(小数点):代表一定有一个任意字符
的意思;*
(星星号):代表重复前一个字符, 0 到无穷多次
的意思,为组合形态
这样讲不好懂,我们直接做个练习吧!假设我需要找出 g??d 的字串,亦即共有四个字符, 起头是 g 而结束是 d ,我可以这样做:
grep -n 'g..d' regular_express.txt
因为强调 g 与 d 之间一定要存在两个字符,因此,第 13 行的 god 与第 14 行的 gd 就不会被列出来啦!
再来,如果我想要列出有 oo,ooo, oooo 等等的数据, 也就是说,至少要有两个(含) o 以上,该如何是好?
是 o* 还是 oo* 还是 ooo* 呢? 虽然你可以试看看结果, 不过结果太占版面了 @_@ ,所以,我这里就直接说明。
因为 * 代表的是 重复 0 个或多个前面的 RE 字符
的意义, 因此, o*
代表的是: 拥有空字符或一个 o 以上的字符
, 特别注意,因为允许空字符
(就是有没有字符都可以的意思),因此, grep -n 'o*' regular_express.txt
将会把所有的数据都打印出来屏幕上!那如果是 oo*
呢?则第一个 o 肯定必须要存在,第二个 o 则是可有可无的多个 o , 所以,凡是含有 o, oo, ooo, oooo 等等,都可以被列出来.
同理,当我们需要 至少两个 o 以上的字串
时,就需要 ooo*
,亦即是:
grep -n 'ooo*' regular_express.txt
如果我想要字串开头与结尾都是 g ,但是两个 g 之间仅能存在至少一个 o ,亦即是 gog,
goog, gooog.... 等等,那该如何?
grep -n 'goo*g' regular_express.txt
如此了解了吗?再来一题,如果我想要找出 g 开头与 g 结尾的字串,当中的字符可有可无,那该如何是好?是 “g*g” 吗?
grep -n 'g*g' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
3:Football game is not use feet only.
9:Oh! The soup taste good.
13:Oh! My god!
14:The gd software is a library for drafting programs.
16:The worldis the same with "glad".
17:I like dog.
18:google is the best tools for search keyword.
19:goooooogle yes!
20:go! go! Let's go.
但测试的结果竟然出现这么多行?太诡异了吧?其实一点也不诡异,因为 gg 里面的 g 代表 空字符或一个以上的 g
在加上后面的 g ,因此,整个 RE 的内容就是 g, gg, ggg, gggg , 因此,只要该行当中拥有一个以上的 g 就符合所需了!
那该如何得到我们的 g....g 的需求呢?呵呵!就利用任意一个字符 .
啊! 亦即是: g.*g
的作法,因为 *
可以是 0 或多个重复前面的字符,而 . 是任意字符,所以: .*
就代表零个或多个任意字符 的意思啦!
所以它的正则表达式如下:
grep -n 'g.*g' regular_express.txt
如果我想要找出 “ 任意数字 ” 的行列呢?因为仅有数字,所以就成为
grep -n '[0-9][0-9]*' regular_express.txt
当然使用下面的正则表达式也可以得到相同的结果:
grep -n '[0-9]' regular_express.txt
限定连续 RE 字符范围 {}
在上个例题当中,我们可以利用 . 与 RE 字符及 *
来设置 0 个到无限多个重复字符, 那如果我想要限制一个范围区间内的重复字符数呢?举例来说,我想要找出两个到五个 o 的连续字串,该如何作?这时候就得要使用到限定范围的字符 {}
了。 但因为 {
与 }
的符号在 shell 是有特殊意义的,因此, 我们必须要使用跳脱字符 \
来让他失去特殊意义才行。 至于 {}
的语法是这样的,假设我要找到两个 o 的字串,可以是:
grep -n 'o\{2\}' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
9:Oh! The soup taste good.
18:google is the best tools for search keyword.
19:goooooogle yes!
这样看似乎与 ooo* 的字符没有什么差异啊?因为第 19 行有多个 o 依旧也出现了! 好,那么换个搜寻的字串,假设我们要找出 g 后面
接 2 到 5 个 o ,然后再接一个 g 的字串,他会是这样:
grep -n 'go\{2,5\}g' regular_express.txt
18:google is the best tools for search keyword.
嗯!很好!第 19 行终于没有被取用了(因为 19 行有 6 个 o 啊!)。 那么,如果我想要的是 2 个 o 以上的 goooo....g 呢?除了可以是
gooo*g ,也可以是:
grep -n 'go\{2,\}g' regular_express.txt
18:google is the best tools for search keyword.
19:goooooogle yes!
它的后一篇 正则表达式与文件格式化处理(2)-sed工具(主)
参考: <<鸟哥的Linux私房菜-基础学习篇(第四版)>>