原文链接:https://segmentfault.com/a/1190000015117538?utm_source=index-hottest
一、正则表达式简介
1. 正则表达式是什么
正则表达式用于描述字符排列和匹配模式的一种语法规则。 它主要用于字符串的模式分割、匹配、查找及替换操作。
2. 正则表达式与通配符
/ | 正则表达式 | 通配符 |
---|---|---|
匹配主体 | 文件中的内容 | 文件名 |
匹配规则 | 包含匹配 | 完全匹配 |
常用命令 | grep ,awk ,sed | ls ,find ,cp |
3. 通配符
*
:匹配任意0到多个字符?
:匹配任意一个字符[]
:匹配括号中的一个字符
*
匹配任意0到多个字符
目录下有5个文件,1个子目录
[root/tmp/tmp]# ll总用量 0 -rw-r--r-- 1 root root 0 5月 31 03:37 abc.ini -rw-r--r-- 1 root root 0 5月 31 03:37 a.conf -rw-r--r-- 1 root root 0 5月 31 03:37 a.md -rw-r--r-- 1 root root 0 5月 31 03:37 bbb.md -rw-r--r-- 1 root root 0 5月 31 03:37 bc.ini drwxr-xr-x 2 root root 58 5月 31 03:39 sh/
列出目录下所有文件,包含子目录中的文件
[root/tmp/tmp]# ll *-rw-r--r-- 1 root root 0 5月 31 03:37 abc.ini -rw-r--r-- 1 root root 0 5月 31 03:37 a.conf -rw-r--r-- 1 root root 0 5月 31 03:37 a.md -rw-r--r-- 1 root root 0 5月 31 03:37 bbb.md -rw-r--r-- 1 root root 0 5月 31 03:37 bc.ini sh: 总用量 0 -rw-r--r-- 1 root root 0 5月 31 03:39 asd.sh -rw-r--r-- 1 root root 0 5月 31 03:38 qwe.sh -rw-r--r-- 1 root root 0 5月 31 03:39 rty.sh -rw-r--r-- 1 root root 0 5月 31 03:39 zxc.sh
列出以
a
开头和以sh
开头的文件
[root/tmp/tmp]# ll a*-rw-r--r-- 1 root root 0 5月 31 03:37 abc.ini -rw-r--r-- 1 root root 0 5月 31 03:37 a.conf -rw-r--r-- 1 root root 0 5月 31 03:37 a.md [root/tmp/tmp]# ll sh*总用量 0 -rw-r--r-- 1 root root 0 5月 31 03:39 asd.sh -rw-r--r-- 1 root root 0 5月 31 03:38 qwe.sh -rw-r--r-- 1 root root 0 5月 31 03:39 rty.sh -rw-r--r-- 1 root root 0 5月 31 03:39 zxc.sh
因为通配符是完全匹配,所以
a*c
匹配不到文件,必须用a*c*
[root/tmp/tmp]# ll a*cls: 无法访问a*b: 没有那个文件或目录 [root/tmp/tmp]# ll a*c*-rw-r--r-- 1 root root 0 5月 31 03:37 abc.ini -rw-r--r-- 1 root root 0 5月 31 03:37 a.conf
匹配字目录中的文件
[root/tmp/tmp]# ll s*a*ls: 无法访问s*a*: 没有那个文件或目录 [root/tmp/tmp]# ll s*/a*-rw-r--r-- 1 root root 0 5月 31 03:39 sh/asd.sh
?
匹配任意一个字符
[root/tmp/tmp]# ll总用量 0 -rw-r--r-- 1 root root 0 5月 31 03:59 aaa.ini -rw-r--r-- 1 root root 0 5月 31 03:37 aaa.md -rw-r--r-- 1 root root 0 5月 31 03:37 abc.ini -rw-r--r-- 1 root root 0 5月 31 03:37 bbb.md -rw-r--r-- 1 root root 0 5月 31 03:37 cbc.ini drwxr-xr-x 2 root root 58 5月 31 03:39 sh/ [root/tmp/tmp]# find . -name '?bc.ini'./abc.ini ./cbc.ini [root/tmp/tmp]# find . -name '???.md'./bbb.md ./aaa.md [root/tmp/tmp]# find . -name 'a??.ini'./abc.ini ./aaa.ini [root/tmp/tmp]# find . -name 's?'./sh
[]
匹配括号中的一个字符
[root/tmp/tmp]# ll总用量 0 -rw-r--r-- 1 root root 0 5月 31 03:59 aaa.ini -rw-r--r-- 1 root root 0 5月 31 03:37 aaa.md -rw-r--r-- 1 root root 0 5月 31 03:37 abc.ini -rw-r--r-- 1 root root 0 5月 31 03:37 bbb.md -rw-r--r-- 1 root root 0 5月 31 03:37 cbc.ini drwxr-xr-x 2 root root 58 5月 31 03:39 sh/ [root/tmp/tmp]# ll [a-z]bc.ini-rw-r--r-- 1 root root 0 5月 31 03:37 abc.ini -rw-r--r-- 1 root root 0 5月 31 03:37 cbc.ini [root/tmp/tmp]# ll [ab]bc.ini-rw-r--r-- 1 root root 0 5月 31 03:37 abc.ini
二、基础正则表达式
元字符 | 作用 |
---|---|
* | 前一个字符匹配0次或任意多次 |
. | 匹配除了换行符以外的任意一个字符 |
^ | 匹配行首。例如:^hello 会匹配以 hello 开头的行 |
$ | 匹配行尾。例如:hello$ 会匹配以 hello 结尾的行 |
[] | 匹配括号中任意一个字符,只匹配一个字符。例如:[aeiou] 匹配任意一个元音字符[0-9] 匹配任意一个数字[a-z] 匹配任意一个小写字母 |
[^] | 取反,匹配括号中字符以外的任意一个字符。例如:[^0-9] 匹配任意一个非数字字符[^a-z] 匹配任意一个非小写字母字符 |
\ | 转义符,用于取消特殊符号的含义。例如:\. 匹配符号 '.' |
\{n\} | 表示其前面的字符恰好出现n次。 |
\{n,\} | 表示其前面的字符至少出现n次。 |
\{n,m\} | 表示其前面的字符至少出现n次,最多出现m次。 |
0. 测试用文档
使用 grep -n '[正则表达式]' [文件]
命令来输出匹配的行,并显示行号。
test.md
1 a 2 aa 3 aaa 4 aaaa 5 aaaaa 6 7 b 8 bb 9 bbb10 bbbb11 bbbbb1213 ab14 aab15 abcb16 abcde1718 said19 soid20 suud21 sooooood2223 02345624 122345625 12326 344527 425asdf28 dasd1234ff2930 3.141592631 hello world.3233 2018-05-3134 2017-02-223536 192.168.33.1037 255.255.255.25538 0.0.0.0
1. *
前一个字符匹配0次或任意多次
2. .
匹配除了换行符以外的任意一个字符
.*
匹配所有内容,包括空白行s..d
匹配在 s 和 d 之间有两个字符的行
[root/tmp]# grep -n 's..d' test.md18:said19:soid20:suud
a.c
匹配在 a 和 c 之间有一个字符的行
[root/tmp]# grep -n 'a.c' test.md15:abcb16:abcde
a.*d
匹配在 a 和 d 之间有任意0到多个字符的行
[root/tmp]# grep -n 'a.*d' test.md16:abcde18:said27:425asdf28:dasd1234ff
3. ^
匹配行首,$
匹配行尾
^s
匹配以 s 开头的行
[root/tmp]# grep -n '^s' test.md18:said19:soid20:suud21:sooooood
d$
匹配以 d 结尾的行
[root/tmp]# grep -n 'd$' test.md18:said19:soid20:suud21:sooooood
^$
匹配所有空行
[root/tmp]# grep -n '^$' test.md6:12:17:22:29:32:35:
4. []
|匹配括号中任意一个字符,只匹配一个字符。
s[aeiou]id
匹配 s 和 id 之间只有一个元音字母的行
[root/tmp]# grep -n 's[aeiou]id' test.md18:said19:soid
s[aeiou]*d
匹配 s 和 d 之间只有任意0个或多个元音字母的行
[root/tmp]# grep -n 's[aeiou]*d' test.md18:said19:soid20:suud21:sooooood27:425asdf28:dasd1234ff
[4-6]
匹配包含 4-6 之间的任意一个数字的行
[root/tmp]# grep -n '[4-6]' test.md23:02345624:122345626:344527:425asdf28:dasd1234ff30:3.141592633:2018-05-3136:192.168.33.1037:255.255.255.255
^[c-z]
匹配以 c-z 之间的任意一个小写字母开头的行
[root/tmp]# grep -n '^[c-z]' test.md18:said19:soid20:suud21:sooooood28:dasd1234ff31:hello world.
5. [^]
取反,匹配括号中字符以外的任意一个字符
^[^a-z]
匹配不以小写字母开头的行
[root/tmp]# grep -n '^[^a-z]' test.md23:02345624:122345625:12326:344527:425asdf30:3.141592633:2018-05-3134:2017-02-2236:192.168.33.1037:255.255.255.25538:0.0.0.0
[^a-z0-9]
匹配包含非数字和小写字母的行
[root/tmp]# grep -n '[^a-z0-9]' test.md30:3.141592631:hello world.33:2018-05-3134:2017-02-2236:192.168.33.1037:255.255.255.25538:0.0.0.0
6. \
|转义符,用于取消特殊符号的含义
\.
匹配包含 '.' 的行
[root/tmp]# grep -n '\.' test.md30:3.141592631:hello world.36:192.168.33.1037:255.255.255.25538:0.0.0.0
\.$
匹配以 '.' 结尾的行
[root/tmp]# grep -n '\.$' test.md31:hello world.
7. \{n\}
表示其前面的字符恰好出现n次
a\{3\}
匹配 a 连续出现 3 次的行
[root/tmp]# grep -n 'a\{3\}' test.md3:aaa4:aaaa5:aaaaa
[0-9]\{5\}
匹配包含连续5个数字的行
[root/tmp]# grep -n '[0-9]\{5\}' test.md23:02345624:122345630:3.1415926
8. \{n,\}
表示其前面的字符至少出现n次
a\{3,\}
匹配 a 至少连续出现 3 次的行
[root/tmp]# grep -n 'a\{3,\}' test.md3:aaa4:aaaa5:aaaaa
[0-9]\{5,\}
匹配包含至少连续5个数字的行
[root/tmp]# grep -n '[0-9]\{5,\}' test.md23:02345624:122345630:3.1415926
9. \{n,m\}
表示其前面的字符至少出现n次,最多出现m次。
s[a-z]\{2,5\}d
匹配 s 和 d 之间至少有2个字母,最多有5个字母的行
[root/tmp]# grep -n 's[a-z]\{2,5\}d' test.md18:said19:soid20:suud
三、几个实例
1. 匹配日期格式 'YYYY-MM-DD'
并非严格匹配日期格式,实际上是匹配 '9999-99-99'
[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}
[root/tmp]# grep -n '[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}' test.md 33:2018-05-3134:2017-02-22
[0-9]\{4\}\(-[0-9]\{2\}\)\{2\}
[root/tmp]# grep -n '[0-9]\{4\}\(-[0-9]\{2\}\)\{2\}' test.md 33:2018-05-31 34:2017-02-22
2. 匹配IP地址
并非严格匹配IP地址,实际上是匹配 0.0.0.0 - 999.999.999.999,而实际IP地址只到 255.255.255.255
[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}
[root/tmp]# grep -n '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' test.md 36:192.168.33.10 37:255.255.255.255 38:0.0.0.0
[0-9]\{1,3\}\(\.[0-9]\{1,3\}\)\{3\}
[root/tmp]# grep -n '[0-9]\{1,3\}\(\.[0-9]\{1,3\}\)\{3\}' test.md 36:192.168.33.10 37:255.255.255.255 38:0.0.0.0