zoukankan      html  css  js  c++  java
  • 正则表达式与文件格式化处理(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私房菜-基础学习篇(第四版)>>

  • 相关阅读:
    LeetCode OJ 107. Binary Tree Level Order Traversal II
    LeetCode OJ 116. Populating Next Right Pointers in Each Node
    LeetCode OJ 108. Convert Sorted Array to Binary Search Tree
    LeetCode OJ 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode OJ 98. Validate Binary Search Tree
    老程序员解Bug的通用套路
    转载 四年努力,梦归阿里,和大家聊聊成长感悟
    转载面试感悟----一名3年工作经验的程序员应该具备的技能
    Web Service和Servlet的区别
    关于spring xml文件中的xmlns,xsi:schemaLocation
  • 原文地址:https://www.cnblogs.com/freedom-try/p/12113807.html
Copyright © 2011-2022 走看看