【问题标题】:re.sub fails to execute - even if the regex pattern is found?re.sub 无法执行 - 即使找到正则表达式模式?
【发布时间】:2014-08-20 20:20:29
【问题描述】:

考虑这个我在 Python 2.7 上运行的示例:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re

tstr = r'''    <div class="thebibliography">
   <p class="bibitem" ><span class="biblabel">
 [1]<span class="bibsp">   </span></span><a
 id="Xtester"></a><span
class="cmcsc-10">A<span
class="small-caps">k</span><span
class="small-caps">e</span><span
class="small-caps">g</span><span
class="small-caps">c</span><span
class="small-caps">t</span><span
class="small-caps">o</span><span
class="small-caps">r</span>,</span>
   <span
class="cmcsc-10">P. D.</span><span
class="cmcsc-10"> H.  </span> testöng ... .  <span
class="cmti-10">Draftin:</span>
   <a
href="http://www.example.com/test.html" class="url" ><span
class="cmitt-10">http://www.example.com/test.html</span></a> (2001).
</p>
   </div>

'''

# remove <a id>
tout2 = re.sub(r'''<a[\s]*?id=['"].*?['"][\s]*?></a>''', " ", tstr, re.DOTALL)
# remove class= in <a
regstr = r'''(<a.*?)(class=['"].*?['"])([\s]*>)'''
print(  re.findall(regstr, tout2, re.DOTALL))             # finds
print("------") #
print(      re.sub(regstr, "AAAAAAA", tout2, re.DOTALL )) # does nothing?

当我运行它时 - 第一个正则表达式被替换/按预期替换(消失了);然后在输出中我得到:

[('<a\nhref="http://www.example.com/test.html" ', 'class="url"', ' >')]

... 这意味着第二个正则表达式编写正确(找到了所有三个部分)-但是,当我尝试用“AAAAAAA”替换所有这些 sn-p 时-输出的那部分没有任何反应:

------
    <div class="thebibliography">
   <p class="bibitem" ><span class="biblabel">
 [1]<span class="bibsp">   </span></span> <span
class="cmcsc-10">A<span
class="small-caps">k</span><span
class="small-caps">e</span><span
class="small-caps">g</span><span
class="small-caps">c</span><span
class="small-caps">t</span><span
class="small-caps">o</span><span
class="small-caps">r</span>,</span>
   <span
class="cmcsc-10">P. D.</span><span
class="cmcsc-10"> H.  </span> testöng ... .  <span
class="cmti-10">Draftin:</span>
   <a
href="http://www.example.com/test.html" class="url" ><span
class="cmitt-10">http://www.example.com/test.html</span></a> (2001).
</p>
   </div>

显然,正如我所料,这里没有“AAAAAAA”。

有什么问题,我应该怎么做才能让sub 替换显然已经找到的匹配项?

【问题讨论】:

  • 感谢@Jerry 的评论-但是,它们是相同的:首先我打电话给re.findall(regstr, ...,然后我打电话给re.sub(regstr, ...;正则表达式模式存储在字符串regstr 中(这就是我首先将它放在变量中的原因)。干杯!
  • 哦,哎呀。那里有两个不同的res,但我没有看到它们。

标签: python html regex replace html-parsing


【解决方案1】:

为什么不使用 HTML 解析器来解析和修改HTML

例如,使用BeautifulSoupreplace_with()

from bs4 import BeautifulSoup

data = """Your html here"""
soup = BeautifulSoup(data)

for link in soup('a', id=True):
    link.replace_with('AAAAAA')

print(soup.prettify())

这会将所有具有id 属性的链接替换为AAAAAA 文本:

<div class="thebibliography">
<p class="bibitem">
<span class="biblabel">
 [1]
 <span class="bibsp">
 </span>
</span>
AAAAAA
<span class="cmcsc-10">
...

另见:

【讨论】:

  • 谢谢你,@alecxe - 但现在我已经写了一个我可以看到工作的正则表达式,我想知道为什么我不能使用 re.sub 。干杯!
  • @sdaau 不客气,我明白了,看看this famous thread :)
【解决方案2】:

由于滥用 re.sub 方法,您的替换不起作用,如果您查看文档:

re.sub(pattern, repl, string, count=0, flags=0)

但是在您的代码中,您将“标志”放在“计数”位置。这就是 re.DOTALL 标志被忽略的原因,因为它位于错误的位置。

由于您不需要使用计数参数,您可以删除 re.DOTALL 标志并使用内联修饰符:

regstr = r'''(?s)(<a.*?)(class=['"].*?['"])([\s]*>)'''

但是,使用 bs4 之类的东西可能更方便。 (正如您在@alecxe 答案中看到的那样)。

【讨论】:

  • 太棒了,非常感谢@CasimiretHippolyte!事实上,我本可以在 OP 代码中写上flags=re.DOTALL,这样就可以了!很遗憾我今天没有投票。将确保在其他时间投票。再次感谢 - 干杯!
【解决方案3】:

这很简单:Python 标准库参考说语法或re.sub 是:re.sub(pattern, repl, string, count=0, flags=0)。所以你的最后一个子实际上是(re.DOTALL == 16):

re.sub(regstr, "AAAAAAA", tout2, count = 16, flags = 0 )

当你需要时:

re.sub(regstr, "AAAAAAA", tout2, flags = re.DOTALL )

最后一个 sub 完美运行...

【讨论】:

  • 感谢@SergeBallesta - 确实!我首先看到了@CasimiretHippolyte 的回答,所以我接受了;一旦我得到更多:)干杯,我会确保我也在这里投票!
【解决方案4】:

好吧,显然,在这种情况下,我应该使用已编译的正则表达式对象(而不是直接通过 re. 模块调用),而且似乎一切正常(甚至可以使用反向引用)-但我仍然没有了解为什么会出现问题?最终知道为什么会很好......无论如何,这是正确的代码sn-p:

# remove <a id>
tout2 = re.sub(r'''<a[\s]*?id=['"].*?['"][\s]*?></a>''', " ", tstr, re.DOTALL)
# remove class= in <a
regstr = r'''(<a.*?)(class=['"].*?['"])([\s]*>)'''
pat = re.compile(regstr, re.DOTALL)
#~ print(  re.findall(regstr, tout2, re.DOTALL))             # finds
print(  pat.findall(tout2))             # finds
print("------") #
# re.purge() # no need
print(      pat.sub(r'\1AAAAAAA\3', tout2, re.DOTALL )) # does nothing?

...这是输出:

[('<a\nhref="http://www.example.com/test.html" ', 'class="url"', ' >')]
------
    <div class="thebibliography">
   <p class="bibitem" ><span class="biblabel">
 [1]<span class="bibsp">   </span></span> <span
class="cmcsc-10">A<span
class="small-caps">k</span><span
class="small-caps">e</span><span
class="small-caps">g</span><span
class="small-caps">c</span><span
class="small-caps">t</span><span
class="small-caps">o</span><span
class="small-caps">r</span>,</span>
   <span
class="cmcsc-10">P. D.</span><span
class="cmcsc-10"> H.  </span> testöng ... .  <span
class="cmti-10">Draftin:</span>
   <a
href="http://www.example.com/test.html" AAAAAAA ><span
class="cmitt-10">http://www.example.com/test.html</span></a> (2001).
</p>
   </div>

【讨论】:

    【解决方案5】:

    问题是 - 你的论点错误

    Python 2.7 源代码:

    def re.sub(pattern, repl, string, count=0, flags=0):
         //code
    

    在这里,您的参数 re.DOTALL 被视为计数参数。

    修复:改用re.sub(regstr, "AAAAAAA", tout2, flags=re.DOTALL )

    注意:如果您尝试将 compile 与您的正则表达式一起使用,则 sub 可以正常工作。

    【讨论】:

    • 谢谢,@VinayBhargav - 事实上,我刚刚得知这一点;几分钟前我刚刚发布了关于编译模式的发现。干杯!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    相关资源
    最近更新 更多