相信我们都见过类似于这样的寻人启示吧,我们要想在茫茫人海中寻找某个人,就相当于从某些信息筛选出某个有用信息,上面的描述中有具体的描述,比如高龄88,失踪前的穿衣打扮,但也有模糊的描述,比如体重略胖,步履略蹒跚等,这跟我们在一堆信息中要筛选出我们需要的信息一样,有时我们知道具体要查找的内容,而有时只知道大概,类似于这样的筛选我们要借助什么完成呢?这就需要深入了解一下我们今天所提到的——正则表达式
什么是正则表达式?
百度百科解释戳这里点击打开链接,在这里简单总结一下,正则表达式是用于描述一组字符串特征的模式,用来匹配特定的字符串。通过特殊字符+普通字符来进行模式描述,从而达到文本匹配目的的工具。
正则表达式的分类
(1)基本的正则表达式(Basic Regular Expression又叫Basic RegEx,简称BREs)
(2)扩展的正则表达式(Extended Regular Expression又叫Extended RegEx简称EREs)
(3)Perl的正则表达式(Perl Regular Expression又叫Perl RegEx简称PREs)
正则表达式的应用场景
(1)验证:表单提交时,进行用户名密码验证
(2)查找:从大量信息中快速提取指定内容;
(3)替换:将指定格式的文本,进行正则匹配查找,找到之后进行特定替换(vim文本替换)
具体测试正则表达式我们需要用到grep模式匹配命令,我们先来了解一下,在实际应用中我们也可以直接用工具验证点击打开链接
1、grep命令用于打印输出文本中匹配的模式串,它使用正则表达式作为模式匹配的条件。
grep支持以下三种正则表达式引擎,分别用三个参数指定
grep命令的常用参数解析
注:
(1)grep指令后不跟任何参数,表示要使用BRE
(2)正则表达式的Extended规范和Basic规范的不同:
- 在Basic规范下,有些字符?+{}|()应解释为普通字符,要表示特殊字符含义需要加\转义
- 在Extended规范下,?+{}|()应该被理解为特殊含义,要取其字面值,也要对其进行\转义
- grep命令默认支持基础正则表达式,而egrep默认支持扩展正则表达式,因此常用egrep代替grep -E
- fgrep表示快速匹配,不支持正则表达式,没有转义的概念,会对PATTERN中的所有字符进行匹配
正则表达式的基本要素
(1)字符类
(2)数量限定符
(3)位置限定符
(4)特殊符号
下面我们分别来讨论这四个要素
1、字符类
具体实例演示:
2、数量限定符
[root@localhost reg]# echo "lluying" | grep -E --color 'l?'
lluying
[root@localhost reg]# echo "llluying" | grep -E --color 'l?'
llluying
[root@localhost reg]# echo "lying" | grep -E --color 'l?'
lying
[root@localhost reg]# echo "uying" | grep -E --color 'l?'
uying
[root@localhost reg]# echo $?
0 //匹配成功了,grep是贪心匹配
[root@localhost reg]# echo "uying" | grep -E --color 'l+'
[root@localhost reg]# echo "uying" | grep -E --color 'l+'
[root@localhost reg]# echo $?
1 //匹配不成功,至少一次
[root@localhost reg]# echo "llluying" | grep -E --color 'l+'
llluying
[root@localhost reg]# echo "luying" | grep -E --color 'l+'
luying
[root@localhost reg]# echo "luying" | grep -E --color 'l*'
luying
[root@localhost reg]# echo "lurteluying" | grep -E --color 'l*'
lurteluying
[root@localhost reg]# echo "llllllurteluying" | grep -E --color 'l*'
llllllurteluying
[root@localhost reg]# echo "haiuying" | grep -E --color 'l*'
haiuying
[root@localhost reg]# echo $?
0
[root@localhost reg]# echo "lurteluying" | grep -E --color 'l{1}'
lurteluying
[root@localhost reg]# echo "lurteluying" | grep -E --color 'l{2}'
[root@localhost reg]# echo "lurtelluying" | grep -E --color 'l{2}'
lurtelluying
[root@localhost reg]# echo "lurtelluying" | grep -E --color 'l{3}'
[root@localhost reg]# echo "lllurtelluying" | grep -E --color 'l{3}'
lllurtelluying
[root@localhost reg]# echo "lllurtellluying" | grep -E --color 'l{3}'
lllurtellluying
[root@localhost reg]# echo "lllurtellllluying" | grep -E --color 'l{3}'
lllurtellllluying
[root@localhost reg]# echo "lllurtellllluying" | grep -E --color 'l{3,}'
lllurtellllluying
[root@localhost reg]# echo "lllurtelluying" | grep -E --color 'l{3,}'
lllurtelluying
[root@localhost reg]# echo "lurtelluying" | grep -E --color 'l{3,}'
[root@localhost reg]# echo "lurtelluying" | grep -E --color 'l{,3}'
[root@localhost reg]# echo "lurtellluying" | grep -E --color 'l{,3}'
[root@localhost reg]# echo $?
1 //不支持,在相关文档中并未出现,应该是错误或者废弃的用法
[root@localhost reg]# echo "lurtellluying" | grep -E --color 'l{2,4}'
lurtellluying
[root@localhost reg]# echo "lurteluying" | grep -E --color 'l{2,4}'
[root@localhost reg]# echo $?
1
[root@localhost reg]# echo "lurtelluying" | grep -E --color 'l{2,4}'
lurtelluying
[root@localhost reg]# echo "lurtelllllluying" | grep -E --color 'l{2,4}'
lurtelllllluying
3、位置限定符
字符 | 含义 | 举例 |
---|---|---|
^ | 匹配行首的位置 | ^luying匹配位于一行开头的luying |
$ | 匹配行末的位置 | ;$匹配位于一行结尾的;号,^$匹配空行 |
\< | 匹配单词开头的位置 | \<th匹配…this,但不匹配ethernet、tenth |
\> | 匹配单词结尾的位置 | p\>匹配leap…,但不匹配parent、sleepy |
\b | 匹配单词开头或结尾的位置 | \bat\b匹配…at…,但不匹配cat、atend、batch等 |
\B | 匹配非单词开头和结尾的位置 | \Bat\B匹配battery,但不匹配…attend、bat… |
使用用例
[root@localhost reg]# echo "hai ehai hail ahail hai" | grep -E --color '^hai'
hai ehai hail ahail hai
[root@localhost reg]# echo "hai ehai hail ahail hai" | grep -E --color 'hai$'
hai ehai hail ahail hai
[root@localhost reg]# echo "hai ehai hail ahailhai" | grep -E --color 'hai$'
hai ehai hail ahailhai
[root@localhost reg]# echo "hai ehai hai ahailhai" | grep -E --color 'hai$'
hai ehai hai ahailhai
[root@localhost reg]# echo "hai ehai hai ahailhai" | grep -E --color '/bhai/b'
[root@localhost reg]# echo "hai ehai hai ahailhai" | grep -E --color '^hai$'
[root@localhost reg]# echo "hai" | grep -E --color '^hai$'
hai
[root@localhost reg]# echo "hai ehai hai ahailhai" | grep -E --color '\>hai'
[root@localhost reg]# echo "hai ehai hai ahailhai" | grep -E --color '\<hai'
hai ehai hai ahailhai
[root@localhost reg]# echo "hai ehai hai hailhai" | grep -E --color '\<hai'
hai ehai hai hailhai
[root@localhost reg]# echo "hai ehai hai ahailhai" | grep -E --color '\>hai'
[root@localhost reg]# echo $?
1
[root@localhost reg]# echo "haieho ehai hai ahailhai" | grep -E --color '\>hai'
[root@localhost reg]# echo "haieho hai hai ahailhai" | grep -E --color '\>hai'
[root@localhost reg]# echo "haieho haihai hai ahailhai" | grep -E --color '\>hai'
[root@localhost reg]# echo "haieho haihai haielo ahailhai" | grep -E --color '\>hai'
[root@localhost reg]# echo "haieho haihai haielo hailhai" | grep -E --color '\>hai'
[root@localhost reg]# echo "hai ehai hai hailhai" | grep -E --color '\<hai'
hai ehai hai hailhai
[root@localhost reg]# echo "hello ahello hellow hello" | grep -E --color '^hello'
hello ahello hellow hello
[root@localhost reg]# echo "hello ahello hellow hello" | grep -E --color 'hello$'
hello ahello hellow hello
[root@localhost reg]# echo "hello ahello hellow hello" | grep -E --color '^hello$'
[root@localhost reg]# echo $?
1
[root@localhost reg]# echo "hello" | grep -E --color '^hello$'
hello
[root@localhost reg]# echo "hello ahello helloq ahelloy hello" | grep -E --color '\>hello'
[root@localhost reg]# echo $?
1
[root@localhost reg]# echo "hello ahello helloq ahelloy hello" | grep -E --color 'hello\>'
hello ahello helloq ahelloy hello
[root@localhost reg]# echo "hello ahello helloq ahelloy hello" | grep -E --color 'hello\<'
[root@localhost reg]# echo "hello ahello helloq ahelloy hello" | grep -E --color '\<hello\>'
hello ahello helloq ahelloy hello
[root@localhost reg]# echo "hello ahello helloq ahelloy hello" | grep -E --color '\bhello'
hello ahello helloq ahelloy hello
[root@localhost reg]# echo "hello ahello helloq ahelloy hello" | grep -E --color '\bhello\b'
hello ahello helloq ahelloy hello
[root@localhost reg]# echo "hello ahello helloq ahelloy hello" | grep -E --color '\Bhello'
hello ahello helloq ahelloy hello
[root@localhost reg]# echo "hello ahello helloq ahelloy hello" | grep -E --color '\Bhello\B'
hello ahello helloq ahelloy hello //其中 \b 用来限定是目标串中是否有以指定字符串开头的单词,我们称之为词界。 \B 称之为非词界
4、特殊符号
字符 | 含义 | 举例 |
\ | 转义字符,普通字符转义为特殊字符,特殊字符转义 为普通字符 | 普通字符<写成\<表示单词开头的位置,特殊字符.写成\. 以及\写成\\就当作普通字符来匹配 |
() | 将正则表达式的一部分括起来组成一个单元,可以对整 个单元使用数量限定符 | ([0-9]{1,3}\.){3}[0-9]{1,3}匹配IP地址 |
| | 连接两个子表达式,表示或的关系 | n(o|either)匹配no或neither |
使用用例
[root@localhost reg]# echo "abcabcabcdef" | grep -E --color '(abc){3}'
abcabcabcdef //用()表示将包含的内容作为一个整体,作为一个单元,进而可以用数量限定符来进行限定
[root@localhost reg]# echo "abcabcabcabcdef" | grep -E --color '(abc){3}'
abcabcabcabcdef
[root@localhost reg]# echo "abcabcabcabcdef" | grep --color '(abc){3}' //去掉-E选项 表明是基础正则表达式
[root@localhost reg]# echo $?
1 //并没有正常匹配
[root@localhost reg]# echo "abcabcabcabcdef" | grep --color '\(abc\)\{3\}' //加\转义
abcabcabcabcdef
[root@localhost reg]# echo "ad{}()+|?cd" | grep --color '{}()+|?'
ad{}()+|?cd
[root@localhost reg]# echo "ad{}()+|?cd" | grep -E --color '{}()+|?'
ad{}()+|?cd
[root@localhost reg]# echo "ad{}()+|?cd" | grep -E --color '\{\}\(\)\+\|\?' //在Extended规范下, ?+{}|() 应该被理解成特殊含义,要取其字面值,也要对其进行 \ 转义
ad{}()+|?cd
[root@localhost reg]# echo "ad{}()+|?cd" | grep -E --color 'ad'
ad{}()+|?cd
[root@localhost reg]# echo "ad{}()+|?cd" | grep -E --color 'cd'
ad{}()+|?cd
[root@localhost reg]# echo "ad{}()+|?cd" | grep -E --color 'ad|cd' // |用来级联多个条件,只要有任意一个匹配,即可匹配,表示或者关系,我们称之为析取符,再次强调, | 可以用
来级联多个条件
ad{}()+|?cd
其他常用通用字符集及其替换
符号 | 替换正则 | 匹配 |
\d | [0-9] | 数字字符 |
\D | [^0-9] | 非数字字符 |
\w | [a-zA-Z0-9_] | 数字字母下划线 |
\W | [^\w] | 非数字字母下划线 |
\s | [_\r\t\n\f] | 表格,换行等空白区域 |
\S | [^\s] | 非空白区域 |
使用用例
练习:
[root@localhost reg]# cat file4 //搜索手机号码
45625882214
15268654939
18700586318
1110
456.3786358
49822566321
8976255a
123456789h
18700586318g
t13434741456
[root@localhost reg]# grep -E --color '1[34578][0-9]{9}' file4
15268654939
18700586318
18700586318g
t13434741456
[root@localhost reg]# grep -E --color '^1[34578][0-9]{9}$' file4
15268654939
18700586318
[root@localhost reg]# echo 1234 | grep -P --color '^[1-9]\d*$' //非零堆的正整数
1234
[root@localhost reg]# echo a1234 | grep -P --color '^[1-9]\d*$'
[root@localhost reg]# echo $?
1
[root@localhost reg]# echo "1234.56" | grep -E --color '^[1-9][0-9]*\.[0-9]{1,2}$' //非零开头的最多带两位小数的数字
1234.56
[root@localhost reg]# echo "1234.566" | grep -E --color '^[1-9][0-9]*\.[0-9]{1,2}$'
[root@localhost reg]# echo "1234.566 123.54" | grep -E --color '^[1-9][0-9]*\.[0-9]{1,2}$'
[root@localhost reg]# echo $?
1
[root@localhost reg]# echo "abcde345ioAEFHRH" | grep -E --color '^[0-9a-zA-Z]+$' //由数字和26个英文字母组成的字符串
abcde345ioAEFHRH
配合正则表达式使用的工具介绍
sed
- sed是一种流编辑器,是文本处理中非常重要的工具,主要用来自动编辑一个或多个文件,简化对文件的反复操作,编写转换程序等;
- 处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”;
- 接着用sed命令处理缓冲区中的内容,处理完成之后,把缓冲区的内容送往屏幕;
- 接着处理下一行,这样不断重复,直到文件末尾;
- sed默认按照基础正则规则进行匹配;
- 文件内容并没有改变,除非你使用了重定向存储输出;
- 注意:sed命令:先正则匹配后动作
1、基本使用方法:
- /pattern/p:打印匹配pattern的行
[root@localhost reg]# cat file
aaaaaaa
bbbbbbb
ccccccc
ddddddd
ddddddd
[root@localhost reg]# sed '/^.*printf.*;$/d' file3
#include<stdio.h>
int main()
{
return 0;
}
[root@localhost reg]# cat file3
#include<stdio.h>
int main()
{
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
return 0;
}
hhhhhhh
fffffff
[root@localhost reg]# sed '/^a\+$/p' file
aaaaaaa
aaaaaaa
bbbbbbb //sed是把待处理文件的内容联通处理结果一起输出到标准输出的
ccccccc //因此p命令处理把文件内内容打印出来以外还额外打印了一遍pattern的行
ddddddd
ddddddd
hhhhhhh
fffffff
[root@localhost reg]# sed -n '/^a\+$/p' file //要想只输出处理结果,应加上-n选项(相当于grep命令)
aaaaaaa
- /pattern/d:删除匹配pattern的行
[root@localhost reg]# sed '/^.*printf.*;$/d' file3
#include<stdio.h>
int main()
{
return 0;
}
[root@localhost reg]# cat file3
#include<stdio.h>
int main()
{
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
return 0;
}
可以看出,sed命令不会修改原文件,删除命令只表示行不打印输出,而不是从原文件中删去,如果要影响原文件,要使用-i选项
[root@localhost reg]# sed -i '/^.*printf.*;$/d' file3
[root@localhost reg]# cat file3
#include<stdio.h>
int main()
{
return 0;
}
- /pattern/s/pattern1/pattern2/:查找符合pattern的行,将该行第一个匹配pattern1的字符串替换为pattern2
[root@localhost zhengze]# cat file1
#include<stdio.h>
int main()
{
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
return 0;
}
[root@localhost zhengze]# sed '/^.*printf(.*);$/s/^/\/\//' file1
#include<stdio.h>
int main()
{
// printf("hai nihao\n");
// printf("hai nihao\n");
// printf("hai nihao\n");
// printf("hai nihao\n");
// printf("hai nihao\n");
return 0;
}
- /pattern/s/pattern1/pattern2/g:查找符合pattern的行,将该行所有匹配pattern1的字符串替换为pattern2
[root@localhost zhengze]# cat file
aaaaaaaaaaaaaaa
bbbbbbbbbbbbbbb
ccccccccccccccc
ccccccccccccccc
eeeeeeeeeeeeeee
[root@localhost zhengze]# sed '/^a\+/p' file
aaaaaaaaaaaaaaa
aaaaaaaaaaaaaaa
bbbbbbbbbbbbbbb
ccccccccccccccc
ccccccccccccccc
eeeeeeeeeeeeeee
[root@localhost zhengze]# sed '/^a\+/s/a/#a#/' file
#a#aaaaaaaaaaaaaa
bbbbbbbbbbbbbbb
ccccccccccccccc
ccccccccccccccc
eeeeeeeeeeeeeee
[root@localhost zhengze]# sed '/^a\+/s/a/#a#/g' file
#a##a##a##a##a##a##a##a##a##a##a##a##a##a##a#
bbbbbbbbbbbbbbb
ccccccccccccccc
ccccccccccccccc
eeeeeeeeeeeeeee
[root@localhost zhengze]# cat file1
#include<stdio.h>
int main()
{
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
printf("hai nihao\n");
return 0;
}
[root@localhost zhengze]# sed '/^a\+/s/a/#&#/g' file //已匹配字符串标记&,可以表示pattern1之后的所有字符
#a##a##a##a##a##a##a##a##a##a##a##a##a##a##a#
bbbbbbbbbbbbbbb
ccccccccccccccc
ccccccccccccccc
eeeeeeeeeeeeeee
[root@localhost zhengze]# echo "this is luying"
this is luying
[root@localhost zhengze]# echo "this is luying" | sed 's/\w\+/[&]/g'
[this] [is] [luying]
- 子串匹配标记\1\2…\n
[root@localhost zhengze]# echo "hai dalao 456"
hai dalao 456
[root@localhost zhengze]# echo "hai dalao 456" | sed 's/\([0-9]\)\([0-9]\)\([0-9]\)/\3\2\1/'
hai dalao 654
\(……\)用于匹配子串,对于匹配到的第一个子串就标记为\1,依次类推匹配到的第二个结果就是\2,通过堆标签进行重组,从而完成数据逆置
- 定址
- ---->用于决定哪些行进行编辑,地址的形式可以是数字,正则表达式或二者的结合,如果没有指定地址,sed将处理所有行
[root@localhost zhengze]# for i in {a..h};do echo $i;done >> file2 [root@localhost zhengze]# cat file2 a b c d e f g h [root@localhost zhengze]# sed -n '3,5p' file2 //打印3-5行的信息 c d e [root@localhost zhengze]# sed '3,5d' file2 //删除3-5行 a b f g h [root@localhost zhengze]# sed -n '/^f/,/^h/p' file2 //打印以f开头行和以h开头行之间的内容 f g h [root@localhost zhengze]# cat file2 a b c d e f g h [root@localhost zhengze]# sed '/^f/,/^h/d' file2 //删除以f开头和以h开头行之间的内容 a b c d e [root@localhost zhengze]# sed -n '/^a/,3p' file2 //打印以a开头到第3行的内容 a b c [root@localhost zhengze]# sed '/^a/,3d' file2 //删除以a开头到第三行的内容 d e f g h [root@localhost zhengze]# echo $? 0 //sed与grep不同,不管是否找到指定的模式,他的退出状态都是0,只有当命令存在语法错误是退出状态才不是0
2、sed的模式空间和保持空间的区别
- 模式空间:可以想成工程里面的流水线,数据直接在它上面进行处理
- 保持空间:可以想象成仓库,我们在进行数据处理的时候,作为数据的暂存区域
- 正常情况下,如果不显示使用某些高级命令,保持空间不会使用到
3、sed的高级命令
- g:将保持空间中的内容拷贝到模式空间中,原来的模式空间里的内容被清空
- G:将保持空间中的内容追加到模式空间\n后
- h:将模式空间中的内容拷贝到保持空间中,原来的保持空间的内容被清空
- H:将模式空间的内容追加到保持空间\n后
- d:删除pattern中的所有行,并读入下一新行到pattern中
- D:删除multiline pattern中的每一行,不读入下一行
- x:交换保持空间和模式空间的内容
- N:将下一行添加到模式空间中
- n:读取下一行到模式空间中