zoukankan      html  css  js  c++  java
  • Linux正则表达式基础正则表示法

    基础正规表示法(出自鸟哥的LINUX私房菜)

      既然正规表示法是处理字符串的一个标准表示方式,他需要支持的工具程序来辅助, 所以,我们这里就先介绍一个最简单的字符串撷取功能的工具程序,那就是 grep 啰! 在介绍完 grep 的基本功能之后,就进入正规表示法的特殊字符的处理能力了。 

    [root@test root]# grep [-acinv] '搜寻字符串' filename
    参数说明:
    -a :将 binary 档案以 text 档案的方式搜寻数据
    -c :计算找到 '搜寻字符串' 的次数
    -i :忽略大小写的不同,所以大小写视为相同
    -n :顺便输出行号
    -v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行!
    范例:
    [root
    @test root]# grep 'root' /var/log/secure
    /var/log/secure 这个档案中有 root 的那一行秀出来
    [root
    @test root]# grep -v 'root' /var/log/secure
    若该行没有 root 才将数据秀出来到屏幕上!
    [root
    @test root]# last | grep root
    若该行有 root 才将数据秀出来到屏幕上!

      

      好了,我们就开始以 grep 来进行正规表示法的简易说明吧!我们先以底下这个档案来作为范例:

    [root@test root]# vi regular_express.txt 
    "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 is the same with
    "glad".
    I like dog.
    google is the best tools
    for search keyword.
    goooooogle yes
    !
    go
    ! go! Let's go.

      例题一、搜寻特定字符串: 搜寻特定字符串很简单吧?假设我们要从刚刚的档案当中取得 the 这个特定字符串, 最简单的方式就是这样:

    [root@test root]# grep -n 'the' regular_express.txt
    8:I can't finish the test.
    12:the symbol '*' is represented as start.
    15:You are the best is mean you are the no. 1.
    16:The world is the same with "glad".
    18:google is the best tools for search keyword.

      

      那如果想要『反向选择』呢?也就是说,当该行没有 'the' 这个字符串时,才显示在屏幕上,那就直接使用:

    [root@test root]# grep -vn 'the' regular_express.txt

      

      您会发现,屏幕上出现的行列为除了 8,12,15,16,18 五行之外的其它行列! 接下来,如果您想要取得不论大小写的 the 这个字符串,则:

    [root@test root]# grep -in 'the' regular_express.txt
    8:I can't finish the test.
    9:Oh! The soup taste good.
    12:the symbol '*' is represented as start.
    14:The gd software is a library for drafting programs.
    15:You are the best is mean you are the no. 1.
    16:The world is the same with "glad".
    18:google is the best tools for search keyword.

      

      例题二、利用 [] 来搜寻集合字符如果我想要搜寻 test 或 taste 这两个单字时,可以发现到,其实她们有共通的 't?st' 存在~这个时候,我可以这样来搜寻。

    [root@test root]# grep -n 't[ae]st' regular_express.txt
    8:I can't finish the test.
    9:Oh! The soup taste good.

      

      了解了吧?其实 [] 里面不论有几个字符,他都谨代表某『一个』字符, 所以,上面的例子说明了,我需要的字符串是『tast』或『test』两个字符串而已! 而如果想要搜寻到有 oo 的字符时,则使用:

    [root@test root]# grep -n 'oo' 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!

      

      但是,如果我不想要 oo 前面有 g 的话呢?此时,可以利用在集合字符的反向选择 [^] 来达成。

    [root@test root]# grep -n '[^g]oo' regular_express.txt
    2:apple is my favorite food.
    3:Football game is not use feet only.
    18:google is the best tools for search keyword.
    19:goooooogle yes!

      

      意思就是说,我需要的是 oo ,但是 oo 前面不能是 g 就是了! 仔细比较上面两个表格,妳会发现,第 1,9 行不见了,因为 oo 前面出现了 g 所致! 第 2,3 行没有疑问,因为 foo 与 Foo 均可被接受!但是第 18 行明明有 google 的 goo 啊~ 别忘记了,因为该行后面出现了 tool 的 too 啊!所以该行也被列出来~ 也就是说, 18 行里面虽然出现了我们所不要的项目 (goo) 但是由于有需要的项目 (too) , 因此,是符合字符串搜寻的喔!

      至于第 19 行,同样的,因为 goooooogle 里面的 oo 前面可能是 o ,例如: go(ooo)oogle ,所以,这一行也是符合需求的!

      再来,假设我 oo 前面不想要有小写字符,所以,我可以这样写 [^abcd....z]oo , 但是这样似乎不怎么方便,由于小写字符的 ASCII 上编码的顺序是连续的, 因此,我们可以将之简化为底下这样:

    [root@test root]# grep -n '[^a-z]oo' regular_express.txt
    3:Football game is not use feet only.

      也就是说,当我们在一组集合字符中,如果该字符组是连续的,例如大写英文/小写英文/数字等等, 就可以使用[a-z],[A-Z],[0-9]等方式来书写,那么如果我们的要求字符串是数字与英文呢? 呵呵!就将他全部写在一起,变成:[a-zA-Z0-9]。

      例如,我们要取得有数字的那一行,就这样: 

    [root@test root]# grep -n '[0-9]' regular_express.txt
    5:However, this dress is about $ 3183 dollars.
    15:You are the best is mean you are the no. 1.

      

      这样对于 [] 以及 [^] 以及 [] 当中的 - 有了解了吗?! ^_^y

      

      例题三、行首与行尾字符 ^ $: 我们在例题一当中,可以查询到一行字符串里面有 the 的,那如果我想要让 the 只在行首列出呢? 这个时候就得要使用定位字符了!我们可以这样做:

      

    [root@test root]# grep -n '^the' regular_express.txt
    12:the symbol '*' is represented as start.

      此时,就只剩下第 12 行,因为只有第 12 行的行首是 the 开头啊~此外, 如果我想要开头是小写字符的那一行就列出呢?可以这样:

    [root@test root]# grep -n '^[a-z]' regular_express.txt
    2:apple is my favorite food.
    4:this dress doesn't fit me.
    10:motorcycle is cheap than car.
    12:the symbol '*' is represented as start.
    18:google is the best tools for search keyword.
    19:goooooogle yes!

      如果我不想要开头是英文字母,则可以是这样:

    [root@test root]# grep -n '^[^a-zA-Z]' regular_express.txt
    1:"Open Source" is a good mechanism to develop programs.
    20:# I am VBird

      注意到了吧?那个 ^ 符号,在字符集合符号(括号[])之内与之外是不同的! 在 [] 内代表『反向选择』,在 [] 之外则代表定位在行首的意义!要分清楚喔!

      那如果我想要找出来,行尾结束为小数点 (.) 的那一行,该如何处理:

    [root@test root]# grep -n '\.$' 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.
    4:this dress doesn't fit me.
    10:motorcycle is cheap than car.
    11:This window is clear.
    12:the symbol '*' is represented as start.
    15:You are the best is mean you are the no. 1.
    16:The world is the same with "glad".
    17:I like dog.
    18:google is the best tools for search keyword.

      特别注意到,因为小数点具有其它意义(底下会介绍),所以必须要使用跳脱字符(\)来加以解除其特殊意义! 不过,您或许会觉得奇怪,但是第 5~9 行最后面也是 . 啊~怎么无法打印出来?? 这里就牵涉到 Windows 平台的软件对于断行字符的判断问题了!我们使用 cat -A 将第五行拿出来看, 您会发现:

      

    [root@test root]# cat -A regular_express.txt
    However, this dress is about $ 3183 dollars.^M$

      注意到了没?最后面的断行字符应该是 $ 才对,但是,因为 Windows 的 nodepad 会主动加上^M 作为断行的判断,因此,那个 . 自然就不是紧接在 $ 之前喔!这样可以了解 ^ 与 $ 的意义吗? 好了,先不要看底下的解答,自己想一想,那么如果我想要找出来,哪一行是『空白行』, 也就是说,该行并没有输入任何数据,该如何搜寻??

      

    [root@test root]# grep -n '^$' regular_express.txt
    21:

      因为只有行首跟行尾( ^$ ),所以,这样就可以找出空白行啦!再来, 假设您已经知道在一个批次脚本 (shell script) 或者是设定档当中, 空白行与开头为 # 的那一行是批注,因此如果您要将资料列出给别人参考时, 可以将这些数据省略掉,以节省保贵的纸张,那么,您可以怎么作呢? 我们以 /etc/syslog.conf 这个档案来作范例,您可以自行参考一下输出的结果:

    [root@test root]# cat /etc/syslog.conf
    [root@test root]# grep -v '^$' /etc/syslog.conf | grep -v '^#'

      是否节省很多版面啊??

      例题四、任意一个字符 . 与重复字符* 在 bash 的章节当中,我们知道万用字符 * 可以用来代表任意(0或多个)字符, 但是正规表示法并不是万用字符,两者之间是不相同的! 至于正规表示法当中的『 . 』则代表『绝对有一个任意字符』的意思!这样讲不好懂, 我们直接做个练习吧!假设我需要找出 g??d 的字符串,亦即共有四个字符, 起头是 g 而结束是 d ,我可以这样做: 

    [root@test root]# grep -n 'g..d' regular_express.txt
    1:"Open Source" is a good mechanism to develop programs.
    9:Oh! The soup taste good.
    16:The world is the same with "glad".

      因为强调 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* ,亦即是:

      

    [root@test root]# grep -n 'ooo*' 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!

      这样理解 * 的意义了吗?!好了,现在出个练习,如果我想要字符串开头与结尾都是 g, 但是两个 g 之间仅能存在至少一个 o ,亦即是 gog, goog, gooog.... 等等, 那该如何?  

    [root@test root]# grep -n 'goo*g' regular_express.txt
    18:google is the best tools for search keyword.
    19:goooooogle yes!

      如此了解了吗?好,再来一题,如果我想要找出 g 开头与 g 结尾的字符串, 当中的字符可有可无,那该如何是好?是『g*g』吗?

    [root@test root]# 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!

      但测试的结果竟然出现这么多行??太诡异了吧? 其实一点也不诡异,因为 g*g 里面的 g* 代表『空字符或一个以上的 g』在加上后面的 g ,因此,整个 RE 的内容就是 g, gg, ggg, gggg , 因此,只要该行当中拥有一个以上的 g 就符合所需了!

      那该如何得到我们的 g....g 的需求呢?呵呵!就利用任意一个字符『.』啊! 亦即是:『g.*g』的作法,因为 * 可以是 0 或多个重复前面的字符,而 . 是任意字符,所以: 『.* 就代表零个或多个任意字符』的意思啦!

      

    [root@test root]# grep -n 'g.*g' regular_express.txt
    1:"Open Source" is a good mechanism to develop programs.
    14:The gd software is a library for drafting programs.
    18:google is the best tools for search keyword.
    19:goooooogle yes!

      因为是代表 g 开头与 g 结尾,中间任意字符均可接受,所以,第 1 与第 14 行是可接受的喔! 这个 .* 的 RE 表示任意字符是很常见的,希望大家能够理解并且熟悉!

      再出一题,如果我想要找出『任意数字』的行列呢?因为仅有数字,所以就成为:

    [root@test root]# grep -n '[0-9][0-9]*' regular_express.txt
    5:However, this dress is about $ 3183 dollars.
    15:You are the best is mean you are the no. 1.

      虽然使用 grep -n '[0-9]' regular_express.txt 也可以得到相同的结果, 但鸟哥希望大家能够理解上面指令当中 RE 表示法的意义才好!

      例题五、限定连续 RE 字符范围 {}

      在上个例题当中,我们可以利用 . 与 RE 字符及 * 来设定 0 个到无线多个重复字符, 那如果我想要限制一个范围区间内的重复字符数呢?举例来说,我想要找出两个到五个 o 的连续字符串,该如何作?这时候就得要使用到限定范围的字符 {} 了。但因为 { 与 } 的符号在 shell 是有特殊意义的,因此, 我们必须要使用跳脱字符 \ 来让他失去特殊意义才行。至于 {} 的语法是这样的,假设我要找到两个 o 的字符串,可以是:

    [root@test root]# 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 的字符串, 他会是这样:

      

    root@test root]# 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 ,也可以是:

    [root@test root]# grep -n 'go\{2,\}g' regular_express.txt
    18:google is the best tools for search keyword.
    19:goooooogle yes!

      呵呵!就可以找出来啦~

      请特别留意的是,『正规表示法的特殊字符』与一般在指令列输入指令的『万用字符』并不相同, 例如,在万用字符当中,* 代表的是 0 ~ 无限多个字符的意思,但是在正规表示法当中, * 则是重复 0 到多个的前一个 RE 字符的意思~使用的意义并不相同,不要搞混了! (鸟哥我一开始摸正规表示法时就很容易搞混!因为这里是新手最容易搞错的地方,特别小心啊!)

      举例来说,不支持正规表示法的 ls 这个工具中,若我们使用『ls -l * 』代表的是任意档名的档案,而『ls -l a* 』代表的是以 a 为开头的任何档名的档案, 但在正规表示法中,我们要找到含有以 a 为开头的档案,则必须要这样:(需搭配支持正规表示法的工具)

    ls | grep -n '^a.*'

      另外,例如万用字符的反向选择,为 [!range] ,至于正规表示法则是 [^range] 。这样是否了解正规表示法与万用字符的差异啦??

      

      

      

  • 相关阅读:
    MVP模式与MVVM模式
    webpack的配置处理
    leetcode 287 Find the Duplicate Number
    leetcode 152 Maximum Product Subarray
    leetcode 76 Minimum Window Substring
    感知器算法初探
    leetcode 179 Largest Number
    leetcode 33 Search in Rotated Sorted Array
    leetcode 334 Increasing Triplet Subsequence
    朴素贝叶斯分类器初探
  • 原文地址:https://www.cnblogs.com/DanielZheng/p/2133095.html
Copyright © 2011-2022 走看看