大数据学习之正则表达式

tech2022-09-30  61

前天在写Shell的时候感觉正则表达式真的是非常的重要,这也是我之前在处理数据时经常会用的比较多的地方,今天就来给大家做一个详细的介绍,冲!

1、正则表达式的定义

1.理解

正则表达式是你所定义的模式模板,Linux工具可以用它来在过滤结构化数据、半结构化数据及非结构化数据时使用你定义好的正则表达式进行匹配,从大量的数据中过滤出你想要的特定数据。可参考下图理解

正则表达式利用通配符来描述数据流中的一个或多个字符。我们常在Linux中使用其来确定数据,在之前我们在介绍Shell工具的时候就使用过“|”符来筛选数据,这就是简单的正则。

2.正则表达式的类型

使用正则表达式最大的问题在于不止一种类型的正则表达式。Linux中的不同应用程序可能会用不同类型的正则表达式。这其中包括编程语言、Linux实用工具以及主流应用。 正则表达式是通过正则表达式引擎实现的。正则表达式引擎是一套底层软件,负责解释正则表达式模式并使用这些模式进行文本匹配。 在Linux中,有两种流行的正则表达式引擎: POSIX基础正则表达式引擎(BRE) POSIX扩展正则表达式引擎(ERE) 大多数的Linux工具都至少满足BRE规范,能够识别该规范定义的所有模式符号。但是总有些意外,有些工具(sed编辑器)只符合BRE规范的子集。这是出于速度方面的考虑导致的,因为sed编辑器希望能尽可能快地处理数据流中的文本。 BRE通常出现在依赖正则表达式进行文本过滤的编程语言中。它为常见模式提供了高级模式符号和特殊符号,比如匹配数字、单词以及按字母排序的字符。gawk程序用ERE引擎来处理它的正则表达式模式。 由于实现正则表达式的方法真的太多,很难有一个通用的模板,但后边我会给大家介绍常用的正则表达式。

2、BRE

最基本的BRE模式是匹配数据流中的文本字符。

1.纯文本

在sed编辑器和gawk程序中用标准文本字符串来过滤数据。

[atguigu@hadoop102 ~]$ echo "This is a test" | sed -n '/test/p' This is a test [atguigu@hadoop102 ~]$ echo "This is a test" | sed -n '/trial/p' [atguigu@hadoop102 ~]$ echo "This is a test" | gawk '/test/{print $0}' This is a test [atguigu@hadoop102 ~]$ echo "This is a test" | gawk '/trial/{print $0}'

第一个模式定义了一个单词test。sed编辑器和gawk程序脚本用它们各自的print命令打印出匹配该正则表达式模式的所有行。由于echo语句在文本字符中包含了单词test,数据流本文能够匹配所定义的正则表达式模式,因此sed编辑器显示了改行。 第二个模式也定义了一个单词,这次是trail。因为echo语句文本字符串没包含该单词,所以正则表达式模式没有匹配,因此sed和gawk程序都没有打印改行。 你可能注意到了,正则表达式并不关心模式在数据流中的位置。它也不关心模式出现了多少次。一旦正则表达式匹配了文本字符串中任意位置上的模式,它就会将该字符串传回Linux工具。 关键在于将正则表达式模式匹配到数据流文本上。重要的是记住正则表达式对匹配的模式非常挑剔。第一条就是原则就是:正则表达式模式都区分大小写。这意味着它们只会匹配大小写也相符的模式。

[atguigu@hadoop102 ~]$ echo "This is a test" | sed -n '/this/p' [atguigu@hadoop102 ~]$ echo "This is a test" | sed -n '/This/p' This is a test

第一次尝试失败的原因就是因为this没有匹配到,在语句中它是大写的,第二次改成大写的就成功了。 在正则表达式中,你不用写出整个单词。只要定义的文本某个字母出现在数据流中,正则表达式就能够匹配。

[atguigu@hadoop102 ~]$ echo "The books are expensive" | sed -n '/book/p' The books are expensive

尽管数据流中的文本是books,但数据中含有正则表达式book,因此正则表达式模式跟数据匹配。当然,反之正则表达式就不成立了。

[atguigu@hadoop102 ~]$ echo "The book is exprnsive" | sed -n '/books/p'

完整的正则表达式文本并未在数据流中出现,因此匹配失败。sed编辑器不会显示任何文本。你也不用局限在正则表达式中只用单个文本单词,可以在正则表达式中使用空格和数字。

[atguigu@hadoop102 ~]$ echo "This is line number 1" | sed -n '/ber 1/p' This is line number 1

在正则表达式中,空格和其他的字符并没有什么区别。

[atguigu@hadoop102 ~]$ echo "This is line number1" | sed -n '/ber 1/p'

如果你在正则表达式中定义了空格,那么它必须出现在数据中。

2.特殊字符

在正则表达式模式中使用文本字符时,有些事情值得注意。在正则表达式定义文本字符时有一些特例。有一些字符在正则表达式中有特别的含义。如果要在文本模式中使用这些字符,那就哈哈哈哈了。 特殊字符有: .*[]^${}+?() 如果要用某个特殊的字符作为文本字符,就必须转义。在转义特殊字符时,你需要在它前面加一个特殊字符来告诉引擎应该将接下来的字符当作普通的文本字符。这个特殊字符就是反斜线(\)。 举个例子,如果要查找文本中的美元符,只要在它前面加个反斜线。

[atguigu@hadoop102 ~]$ cat data2 The cost is $4.00 [atguigu@hadoop102 ~]$ sed -n '/\$/p' data2 The cost is $4.00

由于反斜线是特殊字符,如果要在正则表达式中使用它,你就必须对其转义,这样就产生了两个反斜线。

[atguigu@hadoop102 ~]$ echo "\ is a special character" | sed -n '/\\/p' \ is a special character

最终,尽管正斜线不是正则表达式的特殊字符,但如果他出现在sed编辑器或gawk程序的正则表达式中,你就会得到一个错误哦。

[atguigu@hadoop102 ~]$ echo "3 / 2" | sed -n '///p' sed: -e expression #1, char 3: unknown command: `/'

要使用正斜线,也需要转义。

[atguigu@hadoop102 ~]$ echo "3 / 2" | sed -n '/\//p' 3 / 2

3.锚字符

默认情况下,当指定一个正则表达式模式时,只要出现在数据流中的任何地方,它就能匹配。有两个特殊字符可以用来将模式锁定在数据流中的行首或行尾。 (1)锁定在行首 脱字符(^)定义从数据流中文本行的行首开始的模式。如果模式出现在行首之外的位置,正则表达式模式则无法匹配。 要使用脱字符,就必须将它放在正则表达式中指定的模式前面。脱字符会在每个换行符决定的新数据行首检模式。

[atguigu@hadoop102 ~]$ cat data3 s is a test line. this is another test line. A line that tests this feature. Yet more testing of this [atguigu@hadoop102 ~]$ sed -n '/^this/p' data3 this is another test line.

只要模式出现在新行的行首,脱字符就能够发现它。 如果你将脱字符放到模式开头之外的其他位置,那么它就跟普通字符一样,不再是特殊字符了。 (2)锁定在行尾 跟在行首查找模式相反的就是在行尾查找。特殊字符美元符($)定义了行尾锚点。将这个特殊字符放在文本模式之后来指明数据行必须以该文本模式结尾。

[atguigu@hadoop102 ~]$ echo "This is a dog joe" | sed -n '/joe$/p' This is a dog joe [atguigu@hadoop102 ~]$ echo "This is a dog ltc" | sed -n '/joe$/p'

使用结尾文本模式的问题在于你必须要留意到底要查什么。将行尾的joe改成joes它就不在匹配正则表达式了,尽管joe仍然在数据流中。要想匹配,文本模式必须是行的最后一部分。 (3)组合锚点 在一些情况下,可以在同一行中将行首锚点和行尾锚点组合在一起使用。

4.点号字符

特殊字符点号用来匹配除换行符之外的任意单个字符。它必须匹配一个字符,如果在点号字符的位置没有字符,那么模式将不成立。

[atguigu@hadoop102 ~]$ cat data6 This is a test of a line. The cat is sleeping. That is a very nice hat. This test is at line four. at ten o'clock we'll go home. [atguigu@hadoop102 ~]$ sed -n '/.at/p' data6 The cat is sleeping. That is a very nice hat. This test is at line four.

你应该可以明白为什么第一行无法匹配,而第二、三行可以。第四行注意,我们匹配了at,但在at前面并没有任何字符来匹配点号字符。其实是有的!在正则表达式中,空格也是字符,因此at前面的空格刚好匹配了该模式。第五行证明了这点,将at放在行首就不会匹配该模式了。

5.字符组

点号特殊字符在匹配某个字符位置上的任意字符时很有用。但如果你想要限定待匹配的具体 字符呢?在正则表达式中,这称为字符组(character class)。 可以定义用来匹配文本模式中某个位置的一组字符。如果字符组中的某个字符出现在了数据 流中,那它就匹配了该模式。 使用方括号来定义一个字符组。方括号中包含所有你希望出现在该字符组中的字符。然后你 可以在模式中使用整个组,就跟使用其他通配符一样。这需要一点时间来适应,但一旦你适应了,效果可是令人惊叹的。 我们来看一下

[atguigu@hadoop102 ~]$ sed -n '/[ch]at/p' data6 The cat is sleeping. That is a very nice hat.

这里用到的数据文件和点号特殊字符例子中的一样,但得到的结果却不一样。这次我们成功 滤掉了只包含单词at的行。匹配这个模式的单词只有cat和hat。还要注意以at开头的行也没有 匹配。字符组中必须有个字符来匹配相应的位置。 在不太确定某个字符的大小写时,字符组会非常有用。

[atguigu@hadoop102 ~]$ echo "Yes" | sed -n '/[Yy]es/p' Yes [atguigu@hadoop102 ~]$ echo "yEs" | sed -n '/[Yy][Ee][Ss]/p' yEs

字符组不必只含有字母,也可以在其中使用数字。

[atguigu@hadoop102 ~]$ cat data7 This line doesn't contain a number. This line has 1 number on it. This line a number 2 on it. This line has a number 4 on it. [atguigu@hadoop102 ~]$ sed -n '/[0123]/p' data7 This line has 1 number on it. This line a number 2 on it.

这个正则表达式模式匹配了任意含有数字0、1、2或3的行。含有其他数字以及不含有数字的 行都会被忽略掉。 可以将字符组组合在一起,以检查数字是否具备正确的格式,比如电话号码和邮编。但当你 尝试匹配某种特定格式时,必须小心。这里有个匹配邮编出错的例子。

[atguigu@hadoop102 ~]$ cat data8 60633 46201 223001 4353 22203 [atguigu@hadoop102 ~]$ sed -n '/[0123456789][0123456789][0123456789][0123456789][0123456789]/p' data8 60633 46201 223001 22203

这个结果出乎意料。它成功过滤掉了不可能是邮编的那些过短的数字,因为最后一个字符组没有字符可匹配。但它也通过了那个六位数,尽管我们只定义了5个字符组。 记住,正则表达式模式可见于数据流中文本的任何位置。经常有匹配模式的字符之外的其他字符。如果要确保只匹配五位数,就必须将匹配的字符和其他字符分开,要么用空格,要么像这个例子中这样,指明它们就在行首和行尾。

[atguigu@hadoop102 ~]$ sed -n '/^[0123456789][0123456789][0123456789][0123456789][0123456789]$/p' data8 60633 46201 22203

6.排除型字符组

在正则表达式中,也可以反转字符组的作用。可以寻找组中没有的字符,而不是去寻找组中含有的字符。要这么做的话,只要在字符组的开头加个脱字符。

[atguigu@hadoop102 ~]$ sed -n '/[^ch]at/p' data6 This test is at line four.

通过排除型字符组,正则表达式模式会匹配c或h之外的任何字符以及文本模式。由于空格字 符属于这个范围,它通过了模式匹配。但即使是排除,字符组仍然必须匹配一个字符,所以以at 开头的行仍然未能匹配模式。

7.区间

你可能注意到了,我之前演示邮编的例子的时候,必须在每个字符组中列出所有可能的数字,这实在有点麻烦。好在有一种便捷的方法可以让人免受这番劳苦。可以用单破折线符号在字符组中表示字符区间。只需要指定区间的第一个字符、单破折线以及区间的最后一个字符就行了。正则表达式会包括此区间内的任意字符。

[atguigu@hadoop102 ~]$ sed -n '/^[0-9][0-9][0-9][0-9][0-9]$/p' data8 60633 46201 22203

同样的方法也适用于字母。

[atguigu@hadoop102 ~]$ sed -n '/[c-h]at/p' data6 The cat is sleeping. That is a very nice hat.

8.特殊的字符组

除了定义自己的字符组外,BRE还包含了一些特殊的字符组,可用来匹配特定类型的字符。下表介绍了可用的BRE特殊的字符组。

这里就不展示了哈

9.*号

在字符后面放置星号表明该字段必须在匹配模式的文本出现0次或多次

[atguigu@hadoop102 ~]$ echo "ik" | sed -n '/ie*k/p' ik [atguigu@hadoop102 ~]$ echo "iek" | sed -n '/ie*k/p' iek >[atguigu@hadoop102 ~]$ echo "ieek" | sed -n '/ie*k/p' ieek [atguigu@hadoop102 ~]$ echo "ieeek" | sed -n '/ie*k/p' ieeek

3、ERE

ERE模式包括了一些可供Linux应用和工具使用的额外符号。gawk程序能够识别ERE模式,但sed编辑器不能。 注意: 记住,sed编辑器和gawk程序的正则表达式引擎之间是有区别的。gawk程序可以使用大多数扩展正则表达式模式符号,并且能提供一些额外过滤功能,而这些功能都是sed编辑器所不具备的。但正因为如此,gawk程序在处理数据流时通常才比较慢。

1.问号

问号类似于星号,不过有点细微的不同。问号表明前面的字符可以出现0次或1次,但只限于此。它不会匹配多次出现的字符。

[atguigu@hadoop102 ~]$ echo "bt" | awk '/be?t/{print $0}' bt [atguigu@hadoop102 ~]$ echo "bet" | awk '/be?t/{print $0}' bet [atguigu@hadoop102 ~]$ echo "beet" | awk '/be?t/{print $0}'

2.加号

加号是类似于星号的另一个模式符号,但跟问号也有不同。加号表明前面的字符可以出现1次或多次,但必须至少出现1次。如果该字符没有出现,那么模式就不会匹配。

[atguigu@hadoop102 ~]$ echo "beeet" | awk '/be+t/{print $0}' beeet [atguigu@hadoop102 ~]$ echo "beet" | awk '/be+t/{print $0}' beet [atguigu@hadoop102 ~]$ echo "bet" | awk '/be+t/{print $0}' bet [atguigu@hadoop102 ~]$ echo "bt" | awk '/be+t/{print $0}'

3.使用花括号

ERE中的花括号允许你为可重复的正则表达式指定一个上限。这通常称为间隔(interval)。可以用两种格式来指定区间。 注意:默认情况下,gawk程序不会识别正则表达式间隔。必须指定gawk程序的–re- interval命令行选项才能识别正则表达式间隔。

[atguigu@hadoop102 ~]$ echo "bt"| awk --re-interval '/be{1}t/{print $0}' [atguigu@hadoop102 ~]$ echo "bet"| awk --re-interval '/be{1}t/{print $0}' bet [atguigu@hadoop102 ~]$ echo "beet"| awk --re-interval '/be{1}t/{print $0}'

通过指定间隔为1,限定了该字符在匹配模式的字符串中出现的次数。如果该字符出现多次,模式匹配就不成立。

4.管道符

管道符号允许你在检查数据流时,用逻辑OR方式指定正则表达式引擎要用的两个或多个模式。如果任何一个模式匹配了数据流文本,文本就通过测试。如果没有模式匹配,则数据流文本匹配失败。 使用管道符号的格式如下: expr1|expr2|…

[atguigu@hadoop102 ~]$ echo "The cat is asleep" | gawk '/cat|dog/{print $0}' The cat is asleep [atguigu@hadoop102 ~]$ echo "The dog is asleep" | gawk '/cat|dog/{print $0}' The dog is asleep [atguigu@hadoop102 ~]$ echo "The sheep is asleep" | gawk '/cat|dog/{print $0}'

这个例子会在数据流中查找正则表达式cat或dog。正则表达式和管道符号之间不能有空格,否则它们也会被认为是正则表达式模式的一部分。 管道符号两侧的正则表达式可以采用任何正则表达式模(包括字符组)来定义文本。

[atguigu@hadoop102 ~]$ echo "He has a hat" | gawk '/[ch]at|dog/{print $0}' He has a hat

这个例子会匹配数据流文本中的cat、hat或dog。

5.表达式分组

正则表达式模式也可以用圆括号进行分组。当你将正则表达式模式分组时,该组会被视为一个标准字符。可以像对普通字符一样给该组使用特殊字符。举个例子:

[atguigu@hadoop102 ~]$ echo "Sat" | gawk '/Sat(urday)?/{print $0}' Sat [atguigu@hadoop102 ~]$ echo "Saturday" | gawk '/Sat(urday)?/{print $0}' Saturday

结尾的urday分组以及问号,使得模式能够匹配完整的Saturday或缩写Sat。将分组和管道符号一起使用来创建可能的模式匹配组是很常见的做法。

4.总结

正则表达式内容真的很多,也很复杂,学好非常的不容易,一旦掌握,就会非常舒服!

最新回复(0)