正则表达式 特殊构造用法

查找不能有某个字符串的正则匹配

^((?!hede).)*$
^(?!.*hede).*$

^((?!hede).)*$ 解释:

表达式(?!hede).会往前查找,看看前面是不是没有“hede”字串,如果没有(是其它字符),那么.(点号)就会匹配这些其它字符。这种正则表达式的“查找”也叫做“zero-width-assertions”(零宽度断言),因为它不会捕获任何的字符,只是判断。

在上面的例子里,每个空字符都会检查其前面的字符串是否不是‘hede’,如果不是,这.(点号)就是匹配捕捉这个字符。表达式(?!hede).只执行一次,所以,我们将这个表达式用括号包裹成组(group),然后用*(星号)修饰——匹配0次或多次:((?!hede).)**。

你可以理解,正则表达式((?!hede).)*匹配字符串"ABhedeCD"的结果false,因为在e3位置,(?!hede)匹配不合格,它之前有"hede"字符串,也就是包含了指定的字符串。

在正则表达式里, ?! 是否定式向前查找,它帮我们解决了字符串“不包含”匹配的问题。

^(?!.*hede).*$ 解释

在这种情况下我们使用 ^(?!.*hede).*$ 正则表达式 我们将第一个.*移到了零宽度断言的里面。在匹配的时候首先匹配行首的位置,然后接下来是匹配行首后面的位置,要求此位置的后面不能是 .*hede 匹配的字符串,说白了要求此位置的后面不能是xxxxxxxxxxxxxxxxxxhede 类似的字符串,这样就排除了从行首开始后面含有hede的情况了。

延伸的问题:

问题:查找有多个<img>标签的文本, img 与src 之间不能emoji 出现的标签
方案1: 方案1 demo

 # reg_pattern = r'<img(?!.*emoji).*?src="([^"!"]*?\.(gif|png|jpg|webp))!?(.*?)".*?>'

方案1 解释:
本来是想找到img src之间不能有emoji ,根据字符串不能出现某个字符串的正则写法
^(?!.*helloworld).*$ 所以我写成了 <img(?!.emoji).?src 这样,本想着这样可以,但是问题是多个img标签都是在同一个字符串里面,结果变成了 img 到最后src 之间不能有emoji ,所以中间的所有img都匹配不上了! 而且我的写法 .?src 已经是非贪婪模式,还是因为这个(?!.emoji) 变成了贪婪模式

方案二: 方案二 demo

#reg_pattern = r'<img(?![^"]*emoji)[^"]+?src="([^"!"]*?\.(gif|png|jpg|webp))!?(.*?)".*?>'

方案2 解释:由方案一我想到,我的需求是(?!.emoji)不要贪婪模式,然后看了资料写成(?![^"]emoji)以为在(?!)再写条件就可以避免贪婪, 结果原来这种写法是不行的,真正起作用的是 [^"]+?src 要求src前面不能有" 而我们的字符串刚好是防止前面有class="emoji" 恰巧有" 所以看上去才貌似起了不贪婪的作用, 其实(?![^"]*emoji) 不起作用的

最终方案: 最后方案 demo

reg_pattern = r'<img((?!emoji).)*?src=\"([^\"!]*?\.(gif|png|jpg|webp))!?([^\"]*?)\"((?!emoji).)*?>'

解释:看上面 ^(?!.hede).$ 解释

总结:

利用正则排除某字符串的方式有两种:

  • ^(?!.helloworld).$
  • ^((?!helloworld).)*$
    区别是:
    第一种相当于贪婪的模式, 整个字符串不能出现
    第二种可以作为非贪婪模式的补充,限定不能出现的范围


问题: 查找不能有字符串abc的匹配

正则表达式 字符串 结果
r'a(?=bbb)' abbb a
r'abbb' abbb abbb

python 2.7 文档说明 https://docs.python.org/2/library/re.html

(?=...)
Matches if ... matches next, but doesn’t consume any of the string. This is called a ** lookahead assertion **. For example, Isaac (?=Asimov) will match 'Isaac ' only if it’s followed by 'Asimov'.
(?!...)
Matches if ... doesn’t match next. This is a negative lookahead assertion. For example, Isaac (?!Asimov) will match 'Isaac ' only if it’s not followed by 'Asimov'.

** (?=) 可以看出这种形式的作用是判断条件不计入匹配结果,仅仅是判断条件**

(?<=...) **Group references are not supported ** even if they match strings of some fixed length. Note that patterns which start with positive lookbehind assertions will not match at the beginning of the string being searched;

** 说明(?) 里匹配到的内容都不能使用组引用比如\1 \g<1>引用对应的内容**

同理re.sub, re.search的替换也同样适合这种原理

tmp = 'abbb'
s = re.sub(r'a(bbb)', 'accc', tmp) # 整个匹配规则替换
# 结果
accc

s = re.sub(r'a(?=bbb)', 'accc', tmp) # (?=)里面的内容只做判断作用,不作为匹配结果,所以需要匹配某个规则,又不需要整个规则替换,可以用这个模式
# 结果
acccbbb

s = re.sub(r'a(?=bbb)', 'accc\g<1>', tmp)
# 报错:invalid group reference 不是匹配结果,所以不能引用

s = re.sub(r'a(bbb)', 'accc\g<1>', tmp)
# 正常可以引用 
# 结果
acccbbb

s = re.findall(r'a(?=bbb)', 'abbb')
# 结果  不是匹配结果,所以不能引用
 ['a'] 

继续深入(?=)用法

re.findall('a(?=bhc)d', 'abhcd')
所以这个表达式的意思是:
a后边的表达式必须是bhc, 后面是d
结果: []

为什么? 因为这个(?=bhc)只是针对a后面的匹配, 不是针对d前面的,而对d来说,前面其实是没有匹配表达式
SO, d前面必须是a, 而a后面又必须时bhc,所以永远匹配不到任何东西
应该改成这样:
re.findall('a(?=bhc)\w*d', 'abhcd')
结果: ['abhcd']

分组引用问题

s = re.sub(r'a(?P<hello>xyz)', 'xx\g<hello>', 'axyz') # 使用组名引用 

s = re.sub(r'a(xyz)', 'hello \g<1>', 'axyz')  # 使用序号引用

s = re.sub(r'a(xyz)', 'hello \1', 'axyz')  # 乱码

使用组名或者序号\g<1>来引用是没问题的,但是\1 \2引用会出问题 , 查了下资料,直接用\1这种引用的话,如果后面也是数字比如\10就会引用到第10组,所以避免歧义,还是用\g<1>这种吧

(?=) (?!) 实例:

image.png
title = re.sub(r'span\s+style\s*=\s*".*?color:\s*(.*?)[;"].*?>(.*?)</span>', 'font color="\g<1>">\g<2></font>', title)
# \1 \2 不行 要用\g<1>
#  .*?color 是非贪婪模式, .*是匹配所有字符,但是到color就不要匹配,因为非贪婪模式

# 去掉所有非span, strong 的标签
# eg  : a = '<span><p><strong> hello world </p> </strong> </span>'
# 执行后 被去掉了<p></p> 结果是:<span><strong> hello world  </strong> </span>
title = re.sub(r'</?((?!span|strong).)*?>', '', title)   

# 去掉换行和空格, 这里的换行可能要加上\r\n
title = re.sub(r'\n| ', '', title)

title = re.sub(r'color="(.*?)"', color_formater, title)
title = re.sub(r'</?(span).*?>', '', title)
  • 重点讲解
title = re.sub(r'</?((?!span|strong).)*?>', '', title) 

文章上面也有解析相关知识
</?((?!span).)*?> 这里可以拆开几个步骤:

  1. (?!span) 只是针对</ 这个匹配,意思是</ 后面不需不能是span
  2. 对于((?!span).)的 . 其实是可以匹配任何东西的,但是前面第一步说了</必须不能是span, 这样实际上就限定了. 不能是任何东西,只能是非span
  3. 那么((?!span).) 其实是可以看成 (.)*? 普通的组匹配,只不过组里面不能是span
  4. (.)?> 实际上可以看成.?> 非贪婪模式 匹配最近的一个> 结束符

参考:http://www.cnblogs.com/deerchao/archive/2007/02/15/651411.html

正则匹配换行符

需求: 将占位符[photo_0] [photo_1] .. 以及他们后面的换行符,一起替换成图片<img>,所以就需要匹配到换行符, 而换行符可能时\r 、\n 、\r\n 同时存在。做的时候只考虑了\n导致一致匹配不上!

ms_content = re.sub(r'\[photo_(\d+)\](\r\n|\r|\n)?', img_replace_func, content)

def img_replace_func(m):
    """替换图片用到的函数re.sub
        global upload_url_list
    """
    try:
        index = int(m.group(1))
        url = cdn_essay_upload_img_list[index]
        img_html = '' % url
        return img_html
    except Exception, e:
        return ''

相关链接 http://www.cnblogs.com/wangqiguo/archive/2012/05/08/2486548.html

findall VS search VS match 的区别

# 查找所有img标签
 match = re.findall(r'(<img.*?src=(".*?")(.*?)>)', full_content)

src=".?" 是典型的非贪婪模式, 匹配最近的" 也就是匹配src里面的内容
.
?> 也是同样道理,匹配最近的> 也就是整个img 标签的结束

一开始想着用re.search来做, 但是查了以后,search 和 match 都是只匹配一个, 区别是match只从开头匹配, search可以再字符串任意位置匹配。 但是他们的特点是: 只匹配一次!
所以我要想找所有的img标签, 用search就不合适了。 search找出来的group(0, 1, 2)都是针对一个匹配里面的子匹配!而不是多个匹配!

这里要用findall, 返回所有列表

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • re模块手册 本模块提供了和Perl里的正则表达式类似的功能,不关是正则表达式本身还是被搜索的字符串,都可以...
    喜欢吃栗子阅读 3,977评论 0 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 正则表达式到底是什么东西?字符是计算机软件处理文字时最基本的单位,可能是字母,数字,标点符号,空格,换行符,汉字等...
    狮子挽歌阅读 2,134评论 0 9
  • 当前奏缓缓响起,我就知道它是一首能唱进人心坎里的歌。 大家也深有体会:遇到喜欢的歌听前奏就马上能猜...
    叶祖言阅读 1,197评论 3 4
  • 概览 设计优化 Java程序优化 Java程序优化并行程序开发及优化 JVM调优 Java性能调优工具
    骊骅阅读 232评论 0 1