Python re.sub use non-greedy mode (.*?) with end of string ($) it comes greedy!

安稳与你 提交于 2019-12-19 07:28:10

问题


Code:

str = '<br><br />A<br />B'
print(re.sub(r'<br.*?>\w$', '', str))

It is expected to return <br><br />A, but it returns an empty string ''!

Any suggestion?


回答1:


Greediness works from left to right, but not otherwise. It basically means "don't match unless you failed to match". Here's what's going on:

  1. The regex engine matches <br at the start of the string.
  2. .*? is ignored for now, it is lazy.
  3. Try to match >, and succeeds.
  4. Try to match \w and fails. Now it's interesting - the engine starts backtracking, and sees the .*? rule. In this case, . can match the first >, so there's still hope for that match.
  5. This keep happening until the regex reaches the slash. Then >\w can match, but $ fails. Again, the engine comes back to the lazy .* rule, and keeps matching, until it matches<br><br />A<br />B

Luckily, there's an easy solution: By replacing <br[^>]*>\w$ you don't allow matching outside of your tags, so it should replace the last occurrence.
Strictly speaking, this doesn't work well for HTML, because tag attributes can contain > characters, but I assume it's just an example.




回答2:


The non-greediness won't start later on like that. It matches the first <br and will non-greedily match the rest, which actually need to go to the end of the string because you specify the $.

To make it work the way you wanted, use

/<br[^<]*?>\w$/

but usually, it is not recommended to use regex to parse HTML, as some attribute's value can have < or > in it.



来源:https://stackoverflow.com/questions/4273987/python-re-sub-use-non-greedy-mode-with-end-of-string-it-comes-greedy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!