介绍
作为系统管理员、开发人员、质量保证工程师、支持工程师等,我们需要从文件中找到特定的模式,比如一组属于某个范围的IP地址,或者一段时间戳范围,或者一组域名或子域名。我们可能还需要查找特定拼写的单词或在文件中查找可能的拼写错误。这就是正则表达式发挥作用的地方。
正则表达式是用于匹配模式(有时是不匹配模式)的模板。它们提供了一种描述和解析文本的方式。本教程将介绍正则表达式的基本概念,而不涉及任何特定语言的细节。我们将简单地使用egrep来解释这些概念。
正则表达式
正则表达式由两种类型的字符组成:
-
常规文字字符和
-
元字符
是给正则表达式赋予力量的关键。
考虑以下的 country.txt 文件,第一列是国家名称,第二列是国家人口,第三列是大陆。
$ cat country.txt
India,1014003817,Asia
Italy,57634327,Europe
Yemen,1184300,Asia
Argentina,36955182,Latin America
Brazil,172860370,Latin America
Cameroon,15421937,Africa
Japan,126549976,Asia
锚定元字符
我们首先讨论的一组“元字符”是^和$。^和$分别匹配模式的开头和结尾,称为锚定元字符。
要找出所有国家名称以 I 开头的国家,我们使用表达式:
$ egrep '^I' country.txt
India,1014003817,Asia
Italy,57634327,Europe
或者要找出所有大陆名称以 e 结尾的国家,我们可以:
$ egrep 'e$' country.txt
Italy,57634327,Europe
下一个元字符是点(.),它匹配任何一个字符。要匹配所有国家名称恰好为 5 个字符长的行:
$ egrep '^.....,' country.txt
India,1014003817,Asia
Italy,57634327,Europe
Yemen,1184300,Asia
Japan,126549976,Asia
那么如何找出所有以 I 或 J 开头且国家名称为 5 个字符长的行呢?
$ egrep '^[IJ]....,' country.txt
India,1014003817,Asia
Italy,57634327,Europe
Japan,126549976,Asia
[…] 被称为字符集或字符类。在字符集内,只匹配给定字符中的一个。
字符集内的 ^ 取反字符集。以下示例将匹配国家名称为五个字符长,但不以 I 或 J 开头的。
$ egrep '^[^IJ]....,' country.txt
Yemen,1184300,Asia
分组元字符和交替
匹配包含亚洲或非洲的所有行:
$ egrep 'Asia|Africa' country.txt
India,1014003817,Asia
Yemen,1184300,Asia
Cameroon,15421937,Africa
Japan,126549976,Asia
这也可以通过取A和a共同进行。
$ egrep 'A(si|fric)a' country.txt
India,1014003817,Asia
Yemen,1184300,Asia
Cameroon,15421937,Africa
Japan,126549976,Asia
量词
不写
$ egrep '^[IJ]....,' country.txt
我们可以写
$ egrep '^[IJ].{4},' country.txt
其中{}称为量词。它们确定在它们之前的字符应该出现多少次。
我们也可以给出一个范围:
$ egrep '^[IJ].{4,6},' country.txt
India,1014003817,Asia
Italy,57634327,Europe
Japan,126549976,Asia
这将匹配以I或J开头且后面有4到6个字符的国家名。
量词还有一些快捷方式可用。例如,
{0,1}等同于?
$ egrep '^ab{0,1}c$' filename
等同于
$ egrep '^ab?c' filename
{0,}等同于*
$ egrep '^ab{0,}c$' filename
等同于
$ egrep '^ab*c' filename
{1,}等同于+
$ egrep '^ab{1,}c$' filename
等同于
$ egrep '^ab+c' filename
让我们看一些涉及到我们目前已经看过的表达式的示例。这里我们不是从文件中搜索,而是从标准输入中搜索。我们使用的技巧是,我们知道grep(或egrep)搜索一个模式,如果找到一个模式,那么包含该模式的整行将被显示出来。
我们想找出拼写句子the grey colour suit was his favourite的所有可能方式。
表达式将是:
$ egrep 'the gr[ea]y colou?r suit was his favou?rite'
the grey color suit was his favourite
the grey color suit was his favourite
the gray colour suit was his favorite
the gray colour suit was his favorite
从上面的表达式中我们可以看到:
-
grey可以拼写为grey或gray
-
colour可以写作colour或color,这意味着u是可选的,所以我们使用u?
-
类似地,favourite或favorite可以写作favou?rite
那么匹配美国邮政编码呢?
$ egrep '^[0-9]{5}(-[0-9]{4})?$'
83456
83456
83456-
834562
92456-1234
92456-1234
10344-2342-345
再举一个例子,匹配24小时制的所有有效时间。
$ egrep '^([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]'
23:44:02
23:44:02
33:45:11
15:45:33
15:45:33
在上面的例子中,我们说,如果小时的第一个数字是0或1,则第二个数字可以是0到9中的任意一个。但如果第一个数字是2,则第二个数字的允许值是0、1、2或3。
单词边界
编写一个模式以匹配以color结尾的单词,使unicolor、watercolor、multicolor等都能匹配,但不匹配colorless或colorful。尝试自己做这些例子,以熟悉它们:
$ egrep 'color\>'
接下来,匹配colorless和colorful,但不匹配unicolor、watercolor、multicolor等。
$ egrep '\<color'
因此,为了精确匹配单词color,我们这样做:
$ egrep '\<color\>'
反向引用
假设我们想匹配所有双写的单词,如the the或before before,我们必须使用反向引用。反向引用用于记住模式。
这是一个例子:
$ egrep "\<the\> \1"
或者通用的方式:
$ egrep "\<(.*)\> \1"
以上示例可用于查找所有名字中名和姓相同的情况。如果有多组括号,则第二、第三、第四等可以用\2、\3、\4等来引用。
这只是正则表达式强大功能的简介。
Source:
https://www.digitalocean.com/community/tutorials/an-introduction-to-regular-expressions