关于正则表达式
正则表达式可以通过元字符(规则)来匹配查找相关的的字符集合。他与通配符是有区别的。而且相关的使用工具对正则表示的元字符的是有区别的。
首先我们先来了解下常用的元字符及含义(并不是所有的元字符),主要以bash中的grep为使用机制。
字符匹配
.(点)一个任意字符,回车符换行符除外
[ ]匹配所包含的任意一个字符
[^xyz]负值字符集合。匹配未包含的任意字符。
[a-z]字符范围。匹配指定范围内的任意字符。
注意:只有连字符在字符组内部时,并且出现在两个字符之间时,才能表示字符的范围;
如果出字符组的开头,则只能表示连字符本身.
[^a-z]^表示取反;匹配不在指定范围内的任意一个字符。
[:space:] 一个空白字符
[:punct:] 一个(所有)标点符号
[:lower:] 一个小写字母 [a-z] 不能写成[z-a]
[:upper:] 一个大写字母 [A-Z]
[:digit:] 一个数字 [0-9]
[:alnum:] 一个数字和字母 [A-Z0-9a-z]
[:alpha:] 一个大小写字母 [a-zA-Z]
位置锚定
^ 匹配输入字符串的开始位置。行首 写在左侧
$匹配输入字符串的结束位置。写在行尾
\b匹配一个单词边界,
\B匹配非单词边界。
\< \>匹配词(word)的开始(\<)和结束(\>)。
重叠次数
*匹配前面的子表达式、字符零次或多次(大于等于0次)。
+匹配前面的子表达式一次或多次(大于等于1次)
?匹配前面的子表达式零次或一次。(基本表达式需要转意 \)
{n}前面字符匹配n次。 (基本表达式需要转意 \)
{n,}至少匹配n次,至多不管啊 (基本表达式需要转意 \)
{n,m}其中n<=m。最少匹配n次且最多匹配m次。 (基本表达式需要转意 \ )
特殊功能
( ) 将 \( 和 \) 之间的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到
一个临时区域
(一个正则表达式中最多可以保存9个),它们可以用 \1 到\9 的符号来引用。分组中的模式
匹配到的内容,
可由正则表达式引擎记忆在内存中,之后可被引用有编号:自左而后的左括号,以及与其匹配
右括号
(基本表达式需要转意 \)
\n引用第n个括号所匹配到的内容,而非模式本身
|将两个匹配条件进行逻辑“或”(Or)运算。扩展正则表达式
\转义符号,把后面的字符特殊的转为普通,普通的转为特殊
这上面的这些字符没有别的办法就是记住和理解,其实就是规则文字游戏并不是一开始接触时候的时候所认认为的那么难。重要的是先对单个元字符去实验下然后再去组合。综合而言正则表达式就是计算机所能识别的并被人类所能操作的一种语言,他有很多组合方式来实现你所想要的功能。
使用正则表达式之前首先肯定是有需求或者说是目标,然后分析组合匹配规则。在这里我感觉还是使用扩展正则表达式的好,无需纠结。
首先准备一串字符,我放在了/tmp/ceshi
130 120 200 450 12 24 70 140 8000 30
30 120 200 450 12 24 170 140 80
78 30 1800 200 450 12 24 170 40 80
30 1800 200 450 120 24 170 40 70 70 70
389 30 1800 200 450 120 24 1000 40 70
30 30 1800 200 450 120 24 1000 40 70
130120 200 450122470140800030
30120200450122417014080
7830180020045012241704080
3018002004501202417040707070
3893018002004501202410004070
303018002004501202410004070
匹配下以30开头中间必须含有70的字符串:
1、单个匹配以30为开头:需要做行首锚定^30
2、单个含有70: 70
3、组合匹配需要注意中间30和70之间是可以经过任意字符的.*
^30.*70
[root@zhuzw-centos6 tmp]# cat ceshi | grep -E "^30.*70"
30 120 200 450 12 24 170 140 80
30 1800 200 450 120 24 170 40 70 70 70
30 30 1800 200 450 120 24 1000 40 70
30120200450122417014080
3018002004501202417040707070
303018002004501202410004070
再来匹配下以30开头中间必须包含1800以70结尾的字符串:
还是同样的步骤分析几个重要的点
1、30开头:^30
2、中间必须包含1800: 1800前后都有可能存在字符 .*1800.*
3、以70结尾:70$
^30.*1800.*70$
[root@zhuzw-centos6 tmp]# cat ceshi | grep -E "^30.*1800.*70$"
30 1800 200 450 120 24 170 40 70 70 70
30 30 1800 200 450 120 24 1000 40 70
3018002004501202417040707070
303018002004501202410004070
要求30后面需要跟一个空白字符呢?
要求30后面需要跟上1或者3呢?
^30[ ].*1800.*70$
^30[1|3].*1800.*70$
再来试几个简单的实例
1、要求70 至少出现2次最多出现3次
我们需要用到{n,m}其中n<=m。最少匹配n次且最多匹配m次。
70{2,3}是这样吗?我们来试试
[root@zhuzw-centos6 tmp]# cat ceshi | grep -E "70{2,3}"
[root@zhuzw-centos6 tmp]# echo $?
1
执行错误了为什么呢?仔细看看元字符你会发现它们基本上都是针对单个字符.
70{2,3}实际表示的意思应该是700|7000.
那么我们如何匹配多个字符呢?这就用到了().
[root@zhuzw-centos6 tmp]# cat ceshi | grep -E "(70){2,3}"
3018002004501202417040707070
这里需要注意下\n 匹配的是()里面的匹配处来的内容而不是里面的子表达式
n从外圈开始计算,最外圈的为1
[root@zhuzw-centos6 tmp]# cat ceshi | grep -E "(6(7(\<200\>)))*.*\3?.*[ ]70$"
30 1800 200 450 120 24 170 40 70 70 70
389 30 1800 200 450 120 24 1000 40 70
30 30 1800 200 450 120 24 1000 40 70
[root@zhuzw-centos6 tmp]# A400=200
[root@zhuzw-centos6 tmp]# cat ceshi | grep -E "(6(7(\<`echo A400`\>)))*.*\3?.*[ ]70$"
30 1800 200 450 120 24 170 40 70 70 70
389 30 1800 200 450 120 24 1000 40 70
30 30 1800 200 450 120 24 1000 40 70
2、+和?这两个元字符其实用法跟{n,m}是一样的
+可以写成{1,}至少出现1次,m不赋值表示无限制,但是不许符合n的要求。
?可以写成{0,1}
对于 \B \b \< \>呢你可以把上面字符中被空白字符隔开的一组数字看成是一个单词。
\B200\B \b200\b \<200\> 的区别通过下面的匹配输出就能对比出来了。
[root@zhuzw-centos6 tmp]# cat ceshi | grep -E "\B200\B"
30120200450122417014080
7830180020045012241704080
3018002004501202417040707070
3893018002004501202410004070
303018002004501202410004070
[root@zhuzw-centos6 tmp]# cat ceshi | grep -E "\b200\b"
130 120 200 450 12 24 70 140 8000 30
30 120 200 450 12 24 170 140 80
78 30 1800 200 450 12 24 170 40 80
30 1800 200 450 120 24 170 40 70 70 70
389 30 1800 200 450 120 24 1000 40 70
30 30 1800 200 450 120 24 1000 40 70
130120 200 450122470140800030
[root@zhuzw-centos6 tmp]# cat ceshi | grep -E "\<200\>"
130 120 200 450 12 24 70 140 8000 30
30 120 200 450 12 24 170 140 80
78 30 1800 200 450 12 24 170 40 80
30 1800 200 450 120 24 170 40 70 70 70
389 30 1800 200 450 120 24 1000 40 70
30 30 1800 200 450 120 24 1000 40 70
130120 200 450122470140800030
匹配一个邮箱地址
邮箱的格式 zhuzw_1203@126.com
这是126的邮箱名字规则:6~18个字符,可使用字母、数字、下划线,需以字母开头
grep -E "^[[:alpha:]]([a-z]|[A-Z]|[0-9]|[_]){5,17}@([[:alnum:]]+[\.])+[[:alnum:]]+$"
[[:alpha:]]([a-z]|[A-Z]|[0-9]|[_]){5,17}@([[:alnum:]]+[\.])+[[:alnum:]]+\b
字母开头[[:alnum:]]
可使用字母、数字、下划线 :([a-z]|[A-Z]|[0-9]|[_])
6~18个字符:{5,17}注意因为前面已经有开头的字母占一位了
@:@
邮箱后缀格式126.com : ([[:alnum:]]+[\.])+[[:alnum:]]+
英文大小写数字字符至少出现一次,转义.这个符号;把这两个字表达式作为一个组至少出现一次;最后匹配一个英文大小写数字字符至少出现一次。
分组的原因是可能会有126.com.cn 126.163.com.cn 这种格式的出现
好了写到这里正则表达式的笔记和分享暂告一段落。最后呢其实还是大家先去分析下我们的最终目标然后结合语法去写;目标明确才好去实现。正则表达式的实现方式有很多种实现的方式也都不一样不必纠结于简单复杂,熟练多了自然就简洁了。