在Python中以未知的出现顺序捕获不同元素的正则表达式

在Python中以未知的出现顺序捕获不同元素的正则表达式,python,regex,string,string-matching,regex-lookarounds,Python,Regex,String,String Matching,Regex Lookarounds,我正在构建一个正则表达式,用Python从转发的电子邮件中提取标题值。我只对这些标题在电子邮件中的第一次出现感兴趣,我只想捕获冒号后面出现的文本部分 From: ... Sent: ... To: ... Subject: ... 使用re.search搜索上述格式的大多数变体,以下正则表达式可以正常工作: (?:From\s*:\s*)(.*)(?:\n*)(?:Sent\s*:\s*)(.*)(?:\n*)(?:To\s*:\s*)(.*)(?:\n*)(?:Subje

我正在构建一个正则表达式,用Python从转发的电子邮件中提取标题值。我只对这些标题在电子邮件中的第一次出现感兴趣,我只想捕获冒号后面出现的文本部分

From: ...  
Sent: ...   
To: ...   
Subject: ...  
使用
re.search
搜索上述格式的大多数变体,以下正则表达式可以正常工作:

(?:From\s*:\s*)(.*)(?:\n*)(?:Sent\s*:\s*)(.*)(?:\n*)(?:To\s*:\s*)(.*)(?:\n*)(?:Subject\s*:\s*)
但有时,不同的标题部分的顺序不同,并且缺少元素,例如:

Sent: ...    
From: ...  
Subject: ... 

我想我可以使用正向前瞻来匹配任何顺序的标题格式,但我无法让它工作。有人知道如何有效地做到这一点吗?非常感谢您提供的任何帮助。

一种可能是永远不要使用任何字符,并使用lookahead在可选组中捕获您需要的所有内容:

(?=(?:.*^From\s*:\s*)(.*?$)|)(?=(?:.*^Sent\s*:\s*)(.*?$)|)(?=(?:.*^To\s*:\s*)(.*?$)|)(?=(?:.*^Subject\s*:\s*)(.*?$)|)

间隔开,这只是一个类似模式的4个重复,看起来像:

(?=(?:.*^From\s*:\s*)(.*?$)|)
(?=(?:.*^Sent\s*:\s*)(.*?$)|)
(?=(?:.*^To\s*:\s*)(.*?$)|)
(?=(?:.*^Subject\s*:\s*)(.*?$)|)

此外,为了清楚起见,您可以考虑命名捕获组:

(?=(?:.*^From\s*:\s*)(?P<From>.*?$)|)(?=(?:.*^Sent\s*:\s*)(?P<Sent>.*?$)|)(?=(?:.*^To\s*:\s*)(?P<To>.*?$)|)(?=(?:.*^Subject\s*:\s*)(?P<Subject>.*?$)|)
输出为:

(None, 'sent text', 'totext', 'subject text')
尝试以下模式:
\G(发件人:|主题:|发送:|收件人:)(.+)\n

它应该只捕获第一个块的要求由
\G
锚来实现,它确保在上一个块之后满足下一个匹配(发送/发送/发送/主题),因此另一个邮件的标题不匹配,因为它将由电子邮件的内容分隔

Alternation确保它将独立于Sent/To/From/Subject的顺序来匹配报头


我想我不能使用这个库,因为我的数据集是多语言的。这看起来很棒!当我在regex101中尝试它时,它是有效的(唯一的问题是它不只是捕获第一次出现)。然而,出于某种原因,我的python代码在每封电子邮件中都会找到一个匹配项,其中每个值都只捕获一个正则表达式。更新:我忘了设置m和s标志。它现在工作得很好!你知道如何调整它以只返回每个不同部分的第一个匹配项吗?让标签文本之前的所有量词变为懒惰而不是贪婪,例如
(?)=(?:.*^From
对不起,我的意思与此不同。假设第一个标题块只包含From、Sent、To,第二个标题块包含From、Sent、To、Subject,那么我不希望结果包含第二个转发的标题行,但现在捕获了一个标题行,因为第一个标题块不包含该标题行。您能一个输入和期望输出的更完整的例子?您可能要求一行中没有两个换行符
(None, 'sent text', 'totext', 'subject text')