Python:正则表达式中的可选组

时间:2016-10-22 19:01:14

标签: python regex python-3.x

我正在尝试解析某个文档中的HTML img标记,特别是我想查找图像的所有srcalttitle属性。属性始终采用相同的顺序,但titlealt 是可选的,它们可能不存在。

我试图在我的正则表达式中使用(?:title="(.*?)")?选择组可选,但它不起作用。任何帮助将不胜感激。

example = '<img class="alignnone wp-image-4170 size-full" title="example_title" src="http://www.example.com/wp-content/uploads/2016/07/example.jpg" alt="example_alt" width="300" height="430" />'
re.search(r'(?:title="(.*?)")?.*?src="(.*?)".*?(?:alt="(.*?)")?', example).groups()
>>> (None, 'http://www.example.com/wp-content/uploads/2016/07/example.jpg', None)

预期结果将是:

('example_title', 'http://www.example.com/wp-content/uploads/2016/07/example.jpg', 'example_alt')

1 个答案:

答案 0 :(得分:4)

您可以通过移动第一个非捕获组中的第一个.*?来获得匹配的标题:

>>> re.search(r'(?:title="(.*?)".*?)?src="(.*?)".*?(?:alt="(.*?)")?', example).groups()
('example_title',
 'http://www.example.com/wp-content/uploads/2016/07/example.jpg',
 None)

正则表达式的问题在于它包含。*在可选组之后。这意味着正好在字符串的开头,正则表达式被允许&#34;与可选组不匹配(因为它是可选的),而是继续前进以匹配后面的内容。由于它是.*?之后的东西,它将匹配任何东西,这总是成功的,它不需要匹配你的标题组。它只是使用.*?来匹配从字符串开头到&#34; src&#34;的所有内容,然后匹配&#34; src&#34;。移动非捕获组内的.*?会强制它与&#34;任何东西&#34;除非它首先与标题相符;那么它只会匹配&#34; src&#34;如果它一直向前推进其搜索位置而没有首先找到标题。

正如评论中所提到的,以这种方式解析HTML并不是一个好主意。你的问题实际上是为什么的例证。当你写(?:title="(.*?)")?.*?时,你可能正在思考&#34;一个可选的标题后跟任何东西&#34;,但问题是&#34;任何&#34;也可以包括一个标题,所以它实际上意味着&#34;要么是字符串开头的标题,要么跟着任何东西,或者只是任何东西(包括我们将忽略的标题)&#34;。当您尝试将title=等特定匹配项与.*等通用匹配项结合使用时,您尝试捕获的内容可能会被.*混淆,而不是通过更具体的组捕获。此外,您的代码假定title,src和alt将始终按该顺序出现,但它们可能以任何顺序出现,在这种情况下,正则表达式将无法正确捕获它们。