Python 正则笔记--零宽断言

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 正则笔记--零宽断言相关的知识,希望对你有一定的参考价值。

参考技术A 零宽断言正如它的名字一样,是一种零宽度的匹配,它匹配到的内容不会保存到匹配结果中去,最终匹配结果只是一个位置(并不消耗字符串)。

例子:(?<=一)年(?=半)匹配前面是一和后面是半中的年字

例子:(?<!余)年(?!余) 匹配前面和后面不是余的年字

grep零宽断言&正则表达式

一、grep零宽断言:
(匹配宽度为零,满足一定的条件/断言)
零宽断言用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像 \b ^ $ \< \> 这样的锚定作用,用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。 断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。
分为四种:
1)先行断言 (?=exp)//表示匹配表达式前面的位置
例如 [a-z]*(?=ing) 可以匹配 cooking 和 singing 中的 cook 与 sing
注意:先行断言的执行步骤是这样的先从要匹配的字符串中的最右端找到第一个 ing (也就是先行断言中的表达式)然后 再匹配其前面的表达式,若无法匹配则继续查找第二个 ing 再匹配第二个 ing 前面的字符串,若能匹配则匹配,符合正则的贪婪性。
例如: .*(?=ing) 可以匹配 "cooking singing" 中的 "cooking sing" 而不是 cook

2)后发断言 (?<=exp) //表示匹配表达式后面的位置
例如(?<=abc).* 可以匹配 abcdefg 中的 defg

3)负向零宽断言 (?!exp) 也是匹配一个零宽度的位置,不过这个位置的“断言”取表达式的反值,
例如 (?!exp) 表示 "exp" 前面的位置,如果 "exp" 不成立 ,匹配这个位置;如果 "exp" 成立,则不匹配。
同样,负向零宽断言也有“先行”和“后发”两种,负向零宽后发断言为 (?<!exp)

负向零宽后发断言(?<!exp)
负向零宽先行断言 (?!exp)
负向零宽断言要注意的跟正向的一样。

常用分组语法 //分类 代码/语法 说明
捕获 (exp) 匹配exp,并捕获文本到自动命名的组里
(?<name>exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号
零宽断言 (?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置
(?!exp) 匹配后面跟的不是exp的位置
(?<!exp) 匹配前面不是exp的位置
注释 (?#comment) 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读

aaa bbb CD="123" fd  //取出CD的值
grep -oP '(?<=CD=")\d+' file
以 CD=" 为后发断言,匹配它后面的多个数字。

实例:

create_db_msg: {"rdsj817z94agw6656d42":["drds_mt_revu_0008","drds_mt_revu_0009","drds_mt_revu_0010","drds_mt_revu_0011","drds_mt_revu_0012","drds_mt_revu_0013","drds_mt_revu_0014","drds_mt_revu_0015"],"rdsb4sk15ab96g03gezp":["drds_mt_revu_0000","drds_mt_revu_0001","drds_mt_revu_0002","drds_mt_revu_0003","drds_mt_revu_0004","drds_mt_revu_0005","drds_mt_revu_0006","drds_mt_revu_0007"],"rdsv3q667r37agb27k8a":["drds_mt_revu_0016","drds_mt_revu_0017","drds_mt_revu_0018","drds_mt_revu_0019","drds_mt_revu_0020","drds_mt_revu_0021","drds_mt_revu_0022","drds_mt_revu_0023"]}
[[email protected] test]# cat file  |grep -oP '(?<=")rds.*?(?=":)'  | sort | uniq 
rdsb4sk15ab96g03gezp
rdsj817z94agw6656d42
rdsv3q667r37agb27k8a


注意:这里的 rds.*?中的?有特殊意义,默认rds.*会贪婪匹配到最后一个

二、正则表达式的30min
\btom\b //“\b"中间tom代表是一个单词
\d 表示一个数字
\d{2}-\d{8}。 这里\d后面的{2}({8})的意思是前面\d必须连续重复匹配2次(8次)。
\s匹配任意的空白符,包括空格,制表符(Tab),换行符,中文全角空格等。
\w匹配字母或数字或下划线或汉字等。
.     匹配除换行符以外的任意字符
\d     匹配数字
\b     匹配单词的开始或结束
^     匹配字符串的开始  //^和$匹配的是行
$     匹配字符串的结束

^\d{5,12}$ //填写的QQ号必须为5位到12位数字

备注:"\d"等这些字符只有在perl{正则支持的相对完整} 中能够使用

转义):
    \字符
重复):
    *     重复零次或更多次
    +     重复一次或更多次
    ?     重复零次或一次
    {n}     重复n次
    {n,}     重复n次或更多次
    {n,m}     重复n到m次

[[email protected] test]# ifconfig   |grep -oP "\b(\d{1,}\.)(\d{1,3}\.)(\d{1,3}\.)\d{1,3}\b"  //取出ip地址
10.25.57.183
255.255.252.0
10.25.59.255
255.255.252.0
127.0.0.1
255.0.0.0

字符类)
    [.?!]匹配标点符号(.或?或!)。
    [0-9]代表的含意与\d就是完全一致的
    [a-z0-9A-Z_]也完全等同于\w  
    \(?0\d{2}[) -]?\d{8} //匹配(010)88886666,或022-22334455,或02912345678等
        ( 出现0或者1次,接着是数字0,字符出现2次

[[email protected] test]# cat file
(010)88886666
022-22334455
02912345678
[[email protected] test]# cat file  |egrep "\(?[[:digit:]]{3}\)?\-?[[:digit:]]{8}"
[[email protected] test]# cat file  |grep "(\?[[:digit:]]\{3\})\?\-\?[[:digit:]]\{8\}"
[[email protected] test]# cat file  |egrep "\(?0[[:digit:]]{2}[)-]?[[:digit:]]{8}"
grep中"("和egrep中的"\("一样,
grep中的"\?"和egrep中的"?"一样

分枝条件):
0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)。
分组):
[[email protected] test]# ifconfig | egrep -o "([[:digit:]]{1,3}\.){3}[[:digit:]]"
192.168.3.1
192.168.3.2
255.255.255.0
127.0.0.1
255.0.0.0

((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?) //匹配ip地址
[[email protected] test]# ifconfig |egrep -o "(2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?\.){3}(2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?)"

反义):
\W  匹配任意不是字母,数字,下划线,汉字的字符
\S  匹配任意不是空白符的字符
\D  匹配任意非数字的字符
\B  匹配不是单词开头或结束的位置
[^x]  匹配除了x以外的任意字符
[^aeiou]  匹配除了aeiou这几个字母以外的任意字符

例子:\S+匹配不包含空白符的字符串。
<a[^>]+>匹配用尖括号括起来的以a开头的字符串。

后向应用):
后向引用用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本。
\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, 或者kitty kitty。

常用分组语法): //分类  代码/语法  说明
==============================================================
捕获  
  (exp)  匹配exp,并捕获文本到自动命名的组里
  (?<name>exp)  匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
  (?:exp)  匹配exp,不捕获匹配的文本,也不给此分组分配组号
零宽断言  
  (?=exp)  匹配exp前面的位置
  (?<=exp)  匹配exp后面的位置
  (?!exp)  匹配后面跟的不是exp的位置
  (?<!exp)  匹配前面不是exp的位置
注释  (?#comment)  这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读
第三个(?:exp)不会改变正则表达式的处理方式,只是这样的组匹配的内容不会像前两种那样被捕获到某个组里面,也不会拥有组号。

贪婪与懒惰):
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。
加入需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复
但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:
[[email protected] test]# echo "aababaab" |grep -oP  "a.*b"
aababaab
[[email protected] test]# echo "aababaab" |grep -oP  "a.*?b"
aab
ab
aab

懒惰限定符://尚未理解到位
代码/语法  说明
*?  重复任意次,但尽可能少重复
+?  重复1次或更多次,但尽可能少重复
??  重复0次或1次,但尽可能少重复
{n,m}?  重复n到m次,但尽可能少重复
{n,}?  重复n次以上,但尽可能少重复

#echo "123,123,123,123" |grep -oP "(\d{1,3})?"
123

#echo "123,456,123,789" |grep -oP "(\d{1,3}\,){1,}?"
123,
456,
123,

[[email protected] /root]  //{n,}?用法
#echo "123,456,123,789" |grep -oP "(\d{1,3}\,){1,}"
123,456,123,

[[email protected] /root]   //零宽对比
#echo "123,456,123,789" |grep -oP "(?<=^).*(?=,)"
123,456,123

[[email protected] /root]
#echo "123,456,123,789" |grep -oP "(?<=^).*?(?=,)"
123

三、正则表达式手册
表达式全集:



字符描述
\将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,“n”匹配字符“n”。“\n”匹配一个换行符。串行“\\”匹配“\”而“\(”则匹配“(”。
^匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。
$匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。
*匹配前面的子表达式零次或多次。例如,zo*能匹配“z”以及“zoo”。*等价于{0,}。
+匹配前面的子表达式一次或多次。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。
?匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“does”或“does”中的“do”。?等价于{0,1}。
{n}n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。
{n,}n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。
{n,m}mn均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。
?当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。
.匹配除“\n”之外的任何单个字符。要匹配包括“\n”在内的任何字符,请使用像“(.|\n)”的模式。
(pattern)匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“\(”或“\)”。
(?:pattern)匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分是很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。
(?=pattern)正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern)正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始
(?<=pattern)反向肯定预查,与正向肯定预查类拟,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。
(?<!pattern)反向否定预查,与正向否定预查类拟,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。
x|y匹配x或y。例如,“z|food”能匹配“z”或“food”。“(z|f)ood”则匹配“zood”或“food”。
[xyz]字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。
[^xyz]负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“p”。
[a-z]字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。
[^a-z]负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。
\b匹配一个单词边界,也就是指单词和空格间的位置。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”。
\B匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
\cx匹配由x指明的控制字符。例如,\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“c”字符。
\d匹配一个数字字符。等价于[0-9]。
\D匹配一个非数字字符。等价于[^0-9]。
\f匹配一个换页符。等价于\x0c和\cL。
\n匹配一个换行符。等价于\x0a和\cJ。
\r匹配一个回车符。等价于\x0d和\cM。
\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
\S匹配任何非空白字符。等价于[^ \f\n\r\t\v]。
\t匹配一个制表符。等价于\x09和\cI。
\v匹配一个垂直制表符。等价于\x0b和\cK。
\w匹配包括下划线的任何单词字符。等价于“[A-Za-z0-9_]”。
\W匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。
\xn匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,“\x41”匹配“A”。“\x041”则等价于“\x04&1”。正则表达式中可以使用ASCII编码。.
\num匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“(.)\1”匹配两个连续的相同字符。
\n标识一个八进制转义值或一个向后引用。如果\n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n为一个八进制转义值。
\nm标识一个八进制转义值或一个向后引用。如果\nm之前至少有nm个获得子表达式,则nm为向后引用。如果\nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若nm均为八进制数字(0-7),则\nm将匹配八进制转义值nm
\nml如果n为八进制数字(0-3),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。
\un匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,\u00A9匹配版权符号(?)。

常用匹配:

用户名/^[a-z0-9_-]{3,16}$/
密码/^[a-z0-9_-]{6,18}$/
十六进制值/^#?([a-f0-9]{6}|[a-f0-9]{3})$/
电子邮箱/^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/
 /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/
URL/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/
IP 地址/((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)/
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
HTML 标签/^<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)$/
删除代码\\注释(?<!http:|\S)//.*$
Unicode编码中的汉字范围/^[\u2E80-\u9FFF]+$/


参考博客:
http://tool.oschina.net/uploads/apidocs/jquery/regexp.html
https://www.cnblogs.com/deerchao/archive/2006/08/24/zhengzhe30fengzhongjiaocheng.html

   


以上是关于Python 正则笔记--零宽断言的主要内容,如果未能解决你的问题,请参考以下文章

Python 正则表达式零宽正负向断言的用法及示例代码

Python 正则表达式零宽正负向断言的用法及示例代码

正则表达式零宽断言

15.python正则匹配 元字符转义重复或捕获分组断言:零度断言负向零宽断言贪婪非贪婪引擎选项

正则表达式–零宽断言-赵兴壮

grep零宽断言&正则表达式