前言
对于正则表达式,相信很多人都知道,但是很多人的第一感觉就是难学,因为看第一眼时,觉得完全没有规律可寻,而且全是一堆各种各样的特殊符号,完全不知所云。
其实只是对正则不了解而以,了解了你就会发现,原来就这样啊正则所用的相关字符其实不多,也不难记,更不难懂,唯一难的就是组合起来之后,可读性比较差,而且不容易理解,本文旨在让大家对正则有一个基本的了解,能看得懂简单的正则表达式,写得出简单的正则表达式,用以满足日常开发中的需求即可。
0d{2}-d{8}|0d{3}-d{7} 先来一段正则,如果你对正则不了解,是不是完全不知道这一串字符是什么意思?这不要紧文章会详细解释每个字符的含义的。
什么是正则表达式
正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去匹配符合规则的字符。
正则字符简单介绍
元字符介绍
代码语言:shell复制"^": ^会匹配行或者字符串的起始位置,有时还会匹配整个文档的起始位置.
"$": $会匹配行或字符串的结尾.
"b": 不会消耗任何字符只匹配一个位置,常用于匹配单词边界 如 我想从字符串中"This is Regex"匹配单独的单词 "is" 正则就要写成 "bisb",b 不会匹配is 两边的字符,但它会识别is 两边是否为单词的边界.
"d": 匹配数字,例如要匹配一个固定格式的电话号码以0开头前4位后7位,如0737-5686123,正则:^0ddd-ddddddd$.
"w": 匹配字母,数字,下划线,例如我要匹配"a2345BCD__TTz" 正则:"w ",这里的" "字符为一个量词指重复的次数.
"s": 匹配空格,例如字符 "a b c" 正则:"wswsw" 一个字符后跟一个空格,如有字符间有多个空格直接把"s" 写成 "s " 让空格重复.
".": 匹配除了换行符以外的任何字符,这个算是"w"的加强版了"w"不能匹配空格,如果把字符串加上空格用"w"就受限了,看下用"."是如何匹配字符"a23 4 5 B C D__TTz" 正则:". "
"[abc]": 字符组,匹配包含括号内元素的字符
几种反义
代码语言:shell复制"W" 匹配任意不是字母,数字,下划线 的字符
"S" 匹配任意不是空白符的字符
"D" 匹配任意非数字的字符
"B" 匹配不是单词开头或结束的位置
"[^abc]" 匹配除了abc以外的任意字符
量词
贪婪(贪心),如"*“字符 贪婪量词会首先匹配整个字符串,尝试匹配时,它会选定尽可能多的内容,如果失败则回退一个字符,然后再次尝试回退的过程就叫做回溯,它会每次回退一个字符,直到找到匹配的内容或者没有字符可以回退。相比下面两种贪婪量词对资源的消耗是最大的.
懒惰(勉强),如 “?” 懒惰量词使用另一种方式匹配,它从目标的起始位置开始尝试匹配,每次检查一个字符,并寻找它要匹配的内容,如此循环直到字符结尾处.
占有,如” " 占有量词会覆盖事个目标字符串,然后尝试寻找匹配内容,但它只尝试一次,不会回溯,就好比先抓一把石头,然后从石头中挑出黄金.
“"(贪婪): 重复零次或更多,例如"aaaaaaaa”,匹配字符串中所有的a,正则: “a",会出到所有的字符"a”
“ "(懒惰): 重复一次或更多次,例如"aaaaaaaa” 匹配字符串中所有的a,正则: “a ",会取到字符中所有的a字符,“a “与"a*“不同在于” “至少是一次而”*” 可以是0次.
“?"(占有): 重复零次或一次,例如"aaaaaaaa” 匹配字符串中的a,正则: “a?",只会匹配一次,也就是结果只是单个字符a.
“{n}": 重复n次,例如从"aaaaaaaa” 匹配字符串的a 并重复3次,正则: “a{3}“结果就是取到3个a字符"aaa”;
“{n,m}": 重复n到m次,例如正则 “a{3,4}” 将a重复匹配3次或者4次,所以供匹配的字符可以是三个"aaa"也可以是四个"aaaa” 正则都可以匹配到.
“{n,}": 重复n次或更多次,与{n,m}不同之处就在于匹配的次数将没有上限,但至少要重复n次 如 正则"a{3,}",a至少要重复3次
懒惰限定符
“?": 重复任意次,但尽可能少重复,例如"acbacb”,正则"a.?b” 只会取到第一个"acb” 原本可以全部取到但加了限定符后,只会匹配尽可能少的字符,而"acbacb"最少字符的结果就是"acb”.
“ ?": 重复1次或更多次,但尽可能少重复,与上面一样,只是至少要重复1次
“??": 重复0次或1次,但尽可能少重复,例如 “aaacb” 正则 “a.??b” 只会取到最后的三个字符"acb”
“{n,m}?": 重复n到m次,但尽可能少重复,例如 “aaaaaaaa” 正则 “a{0,m}” 因为最少是0次所以取到结果为空
“{n,}?": 重复n次以上,但尽可能少重复,例如 “aaaaaaa” 正则 “a{1,}” 最少是1次所以取到结果为"a”.
grep 正则表达式
grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。
Unix的grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的扩展,支持更多的re元字符, fgrep就是fixed grep或fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。
grep常用用法
代码语言:shell复制grep [-acinv] [--color=auto] '搜寻字符串' filename
选项与参数:
-a :将 binary 文件以 text 文件的方式搜寻数据
-c :计算找到 '搜寻字符串' 的次数
-i :忽略大小写的不同,所以大小写视为相同
-n :顺便输出行号
-v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行!
--color=auto :可以将找到的关键词部分加上颜色的显示喔!
sed 正则表达式
sed 用法
代码语言:shell复制# 批量替换
sed -i "s/oldstring/newstring/g" grep oldstring -rl path
awk 正则表达式
awk 语法
代码语言:shell复制awk `/REG/{action}`
awk可以读取后接的文件,也可以读取来自前一命令的标准输入,它分别扫描输入数据的每一行,查找当前扫描行中pattern是否匹配。如果匹配,则进行后续动作action。如果pattern不匹配或action部分处理完毕,则继续处理下一行,直到结束。
代码语言:shell复制awk '{
BEGIN{...} #执行前语句
pattern{...} #每一行都会处理的语句,可以有多个
END{...} #执行后要处理的语句
}'
其中BEGIN为处理文本前的操作,一般用于改变FS,OFS,RS,ORS等,BEGIN部分完成之后,awk读取第一行输入,并将第一行的数据填入0,1,2,..,n,NR,NF等变量,然后进入正式处理阶段,待所有行处理完毕之后,进入END部分,END一般用于总结,打印报表等。
正式处理是一个内建的循环,每一次循环读取一行数据(默认RS为换行符),pattern{…}部分可以有多个,它可以使用正则匹配/RE/,算术运算符>,<,…,逻辑运算符&&,||等,当pattern没有时,也即不需要匹配条件,后面的动作{…}会在每一行都执行.
awk 内置变量
变量 | 用法 |
---|---|
$0 | 当前记录(这个变量中存放着整个行的内容) |
$1-$n | 当前记录的第n个字段,字段间由FS分隔 |
FS | 输入字段分隔符 默认是空格或者t |
NF | 当前记录的字段个数 就是有多少列 |
NR | 已经读出的记录数,就是行号,从1开始,如果有多个文件话,这个值也是不断累加中 |
FNR | 当前记录数,与NR不同的是,这个值会是各个文件自己的行号 |
RS | 输入的记录分隔符,默认为换行符 |
OFS | 输出字段分隔符,默认为空格 |
ORS | 输出的记录分隔符,默认为换行符 |
FILENAME | 当前输入文件的名字 |
awk运算符合正则匹配
算术运算符
- awk算术运算符:
!=,>,<,>=,<=
逻辑运算符
&&
多个条件且||
多个条件或
正则匹配
- awk使用的RE为扩展正则表达式,匹配格式为/reg/
- 定位行:
- NR==行号
- 用RE: /^Disk/
- 字符串匹配: ~匹配!~不匹配
/reg/
在整行范围内匹配reg,匹配到就执行后续动作!/reg/
整行没匹配到reg,才执行后续的动作$1~/reg/
只在第一字段匹配reg$1!~/reg/
第一个字段不匹配NR >=2
从第二行开始处理
awk 整则可以和比较运算符结合使用,以便处理更复查的匹配
awk技巧
- awk使用的RE为ERE
- 如果在BEGIN中设置了OFS,只有$0有改动OFS才能生效
printf
与print
的区别:printf
不自动打印换行符,print
则自动打印换行符- gsub的返回值并不是替换后的字符串,而是返回替换的次数
- 字符串常量一定用在"“包围起来,否则当做变量使用,如
$1=="ipaaad"
- awk的for循环为
C-Style
即为for()
,区别于shell中的for i in ...
- awk中可以使用多个分隔符,要封装在方括号里,用'‘包围,以防shell对他们进行解释,如
awk -F '[:/t]'
,使用空格,冒号,tab作为分隔符 - next语句: 从输入文件中取得下一个输入行,在awk命令表顶部重新执行命令,一般用于跳过一些特殊的行
- awk匹配多个条件: `awk ‘/kobe/ && /james/’, 这会匹配的同时有kobe和james的行
- FS默认值是
[/t/n]
,OFS的默认值为空格,RS,ORS的默认值都是换行 - exit语句: 终止AWK程序,但不跳过END语句
{s1;s2;s3;...}
中多个语句用分号隔开if;else if;else
print
后不带任何参数时,相当于print $0
,将会打印整行记录
awk用法
代码语言:shell复制# 统计数据
cat xx.log |awk '{a[$1] =1;} END {for(i in a){print a[i]" "i;}}'
#字符串截取
echo "123456789" | awk '{print substr($0, 5, 2)}'
# 从第二列开始打印
awk -F ":" '{for (i=2;i<=NF;i )printf("%s ", $i);print ""}' xx
# 统计行数
awk 'END{print NR}' test1.sh
# 排序输出
sort -n -k1 kafka_production_12|awk -F ":" '{for (i=1;i<=NF;i )printf("%s ", $i);print ""}'|awk '$2>=1634486400000 && $2<=1634572800000 {print $0}' > kafka_production_10-18-00-00-00-10-19-00-00-00
# 统计IP
awk '{i=$1;count[i] }END{for(i in count)print(i,count[i])}' /var/log/httpd/access_log
# 统计访问次数最多
awk '{a[$1] = 1;} END {for (i in a) printf("%d %sn", a[i], i);}' /var/log/httpd/access_log | sort -n | tail -n 10
# 添加表头
awk 'BEGIN {print "IDtTime"}{printf("%st%sn",$1,$2)| "sort -k1,1 -u -r"}' /var/log/httpd/access_log
# 定制表头
awk 'BEGIN{print "姓名 语文 数学 英语 总成绩";
sum1=0;sum2=0;sum3=0;sumall=0}
{printf "%5s]]]]n",$1,$2,$3,$4,$2 $3 $4;
sum1 =$2;sum2 =$3;sum3 =$4;sumall =$2 $3 $4}
END{printf "%5s]]]]n","总成绩",sum1,sum2,sum3,sumall}'
score.txt | column -t
# awkif使用
awk '{ if($1 == "xxx-'"$i"'")print $2}'
split 使用
代码语言:shell复制# 按大小切割
split -b 500M xx.log -d -a 2 newfile_
# 按行数切割
split -l 100000 xx.log -d -a 2 newfile_