了解用于在 html 中的字符串之间查找字符串的正则表达式模式

Understanding regex pattern used to find string between strings in html

我有以下 html 文件:

<!-- <div class="_5ay5"><table class="uiGrid _51mz" cellspacing="0" cellpadding="0"><tbody><tr class="_51mx"><td class="_51m-"><div class="_u3y"><div class="_5asl"><a class="_47hq _5asm" href="/Dev/videos/1610110089242029/" aria-label="Who said it?" ajaxify="/Dev/videos/1610110089242029/" rel="theater">

为了提取 videos//" 之间的数字串,我使用了以下我发现的方法:

import re 

Source_file = open('source.html').read()
result = re.compile('videos/(.*?)/"').search(Source_file)
print result

我已经尝试通过谷歌搜索解释 (.*?) 在此特定实现中的确切工作原理,但我仍然不清楚。有人可以向我解释一下吗?这就是所谓的 "non-greedy" 匹配吗?如果是,那是什么意思?

.表示任意字符。 * 表示任意次数,包括零次。 ? 确实意味着非贪婪;这意味着它将尝试捕获尽可能少的字符,即,如果正则表达式遇到 /,它可以将其与 . 匹配,但它宁愿不匹配,因为 . 是非贪婪的,并且由于正则表达式中的下一个字符很乐意匹配 /,因此 . 不必匹配。如果你没有 ?,那么 . 会吃掉整个文件的其余部分,因为它会拼命匹配尽可能多的东西,而且因为它匹配所有东西,它会永远持续下去。

可以简单的解释一下:

  • .:匹配任何东西(任何字符),
  • *:任意次数(至少为零次),
  • ?:次数越少越好(因此非贪婪)。
videos/(.*?)/"

作为正则表达式匹配(例如)

videos/1610110089242029/"

和第一个捕获组returns 1610110089242029,因为任何数字都是“任何字符”的一部分,并且其中至少有零个字符。

? 导致这样的事情:

videos/1610110089242029/" something else … "videos/2387423470237509/"

正确匹配 16101100892420292387423470237509 而不是 1610110089242029/" something else … "videos/2387423470237509,因此“尽可能少的次数”,因此“非贪婪”。

本文中的?是重复运算符(+*?)的特殊运算符。在可用的引擎中,这会导致重复 lazynon-greedyreluctant 或其他此类条款。通常重复是贪婪的,这意味着它应该尽可能匹配。所以在大多数现代 perl 兼容引擎中你有三种类型的重复:

.*  # Match any character zero or more times
.*? # Match any character zero or more times until the next match (reluctant)
.*+ # Match any character zero or more times and don't stop matching! (possessive)

可以在此处找到更多信息:http://www.regular-expressions.info/repeat.html#lazy for reluctant/lazy and here: http://www.regular-expressions.info/possessive.html 所有格(我将在本回答中跳过讨论)。

假设我们有字符串 aaaa。我们可以用 /(a+)a/ 来匹配所有的 a。字面意思是

match one or more a's followed by an a.

这将匹配 aaaa。正则表达式是贪婪的,将匹配尽可能多的 a。第一个子匹配是 aaa.

如果我们使用正则表达式 /(a+?)a 这是

reluctantly match one or more as followed by an a
or
match one or more as until we reach another a

也就是只匹配我们需要的。所以在这种情况下,匹配项是 aa,第一个子匹配项是 a。我们只需要匹配一个 a 来满足重复,然后它后面跟着一个 a.

使用正则表达式在 html 标签、引号和类似内容中进行匹配时经常会出现这种情况——通常保留用于 快速和肮脏的 操作。也就是说,使用正则表达式从非常大且复杂的 html 字符串或带有转义序列的引号字符串中提取可能会导致很多问题,但对于特定用例来说它完全没问题。所以在你的情况下我们有:

/Dev/videos/1610110089242029/

表达式需要匹配 videos/ 后跟零个或多个字符后跟 /"。如果只有一个视频URL那还好,不勉强

但是我们有

/videos/1610110089242029/" ... ajaxify="/Dev/videos/1610110089242029/"

毫不勉强,正则表达式将匹配:

1610110089242029/" ... ajaxify="/Dev/videos/1610110089242029

它会尽量匹配,/" 满足 . 就好了。不情愿地,匹配在第一个 /" 处停止(实际上它回溯了,但您可以单独阅读)。因此你只得到你需要的url部分。