正则表达式与文件格式化处理(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 world is 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私房菜-基础学习篇(第四版)>>

posted @ 2019-12-29 00:44  enjoy_jun  阅读(546)  评论(0编辑  收藏  举报