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

Ant*_*kov 0 python regex python-3.x

我试图解析HTML img标记特定文档中,特别是我想找到所有的srcalt以及title图像的属性。属性总是以相同的顺序,但是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)
Run Code Online (Sandbox Code Playgroud)

预期结果将是:

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

Bre*_*arn 6

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

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

正则表达式的问题在于,它在可选组之后包含。*。这意味着在字符串的开头,正则表达式“被允许”不匹配可选组(因为它是可选组),而是继续匹配后面的内容。由于紧随其后的是.*?,它将匹配任何内容,因此它总是成功的,并且不需要匹配您的标题组。它只是使用.*?来匹配从字符串开头到“ src”的所有内容,然后匹配“ src”。.*?在非捕获组内部移动会迫使它与“任何内容”都不匹配,除非它首先与标题匹配;那么只有在不首先找到标题的情况下一直将搜索位置一直推进到该位置时,它才会与“ src”匹配。

正如评论中提到的那样,以这种方式解析HTML不是一个好主意。您的问题实际上是一个说明。在撰写本文时,(?:title="(.*?)")?.*?您可能在考虑“可选标题后跟任何内容”的问题,但问题是“任何内容”还可以包含标题,因此实际上的含义是“要么在标题的开头字符串,后跟任何内容,或仅包含任何内容(包括标题,我们将忽略)”。当您尝试将特定匹配项title=与通用匹配项组合在一起时.*,您尝试捕获的内容可能会被.*而不是与您更特定的组一起捕获。此外,您的代码假定title,src和alt始终按该顺序出现,但是它们可以按任何顺序出现,在这种情况下,您的正则表达式将无法正确捕获它们。