忽略与正则表达式不完全匹配的字符串?

2024-10-01 00:34:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我想用regex返回电子邮件的所有收件人。例如:

Date: Wed, 6 Dec 2000 02:03:00 -0800 (PST)
From: donald.herrick@enron.com
To: brianherrick@email.msn.com, herriceu2@tdprs.state.tx.us, 
    robertherrick@bankunited.com, kristi.demaiolo@enron.com, 
    suresh.raghavan@enron.com, harry.arora@enron.com
Subject: FW: If Santa Answered his mail...
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-From: Donald W Herrick
X-To: brianherrick@email.msn.com, HERRICEU2@tdprs.state.tx.us, RobertHerrick@bankunited.com, Kristi Demaiolo, Suresh Raghavan, Harry Arora
X-cc: 
X-bcc: 

应该返回(从“到:”行)brianherrick@email.msn.com, 邮箱:herriceu2@tdprs.state.tx.us, robertherrick@bankunited.com, 克里斯蒂·德米奥洛@安然公司, 苏雷什·拉哈万@安然公司, 哈里·阿罗拉@安然公司

但是不是(从“X-To:”行)brianherrick@email.msn.com, 邮箱:HERRICEU2@tdprs.state.tx.us, RobertHerrick@bankunited.com。你知道吗

我当前的正则表达式是re.findall([To:\s][\w\.-]+@[\w\.-]+, text),它返回“To:”、“X-To:”和“from:”行中的所有内容。你知道吗

我的问题:

  1. 为什么“发件人:”行上的电子邮件地址也被返回?它 与正则表达式的[To:\s]部分不匹配?!你知道吗
  2. 如何确保只有“收件人:”后面的电子邮件地址是 返回?(即,如何排除以下电子邮件地址 “X到:”?我认为您可以对此使用前瞻断言,但我不确定如何做到这一点?你知道吗

Tags: tocom电子邮件email地址公司收件人us
3条回答

regex模块:无限查找和其他功能

如果您想使用regex,我建议您使用未完成的^{} module而不是re。此正则表达式将返回所有匹配项:

(?<=(?<!X\S+)To:\s*(?:[^@\s]+@[^\,\s]+,\s*)*?)[^@\s]+@[^\,\s]+

示例代码

我在python3.4中对此进行了测试。你知道吗

import regex
subject = """Date: Wed, 6 Dec 2000 02:03:00 -0800 (PST)
From: donald.herrick@enron.com
To: brianherrick@email.msn.com, herriceu2@tdprs.state.tx.us, 
    robertherrick@bankunited.com, kristi.demaiolo@enron.com, 
    suresh.raghavan@enron.com, harry.arora@enron.com
Subject: FW: If Santa Answered his mail...
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-From: Donald W Herrick
X-To: brianherrick@email.msn.com, HERRICEU2@tdprs.state.tx.us, RobertHerrick@bankunited.com, Kristi Demaiolo, Suresh Raghavan, Harry Arora
X-cc: 
X-bcc: """
pattern = "(?<=(?<!X\S+)To:\s*(?:[^@\s]+@[^\,\s]+,\s*)*?)[^@\s]+@[^\,\s]+"

for match in regex.finditer(pattern, subject):
    print(match.group())

输出

brianherrick@email.msn.com
herriceu2@tdprs.state.tx.us
robertherrick@bankunited.com
kristi.demaiolo@enron.com
suresh.raghavan@enron.com
harry.arora@enron.com

解释

  • 我们有一个大的lookback,然后是一个非常基本的电子邮件匹配器:[^@\s]+@[^\,\s]+,它匹配任何不是arrobas或空格字符的字符,然后是arrobas,然后是任何不是逗号或空格字符的字符(输入中电子邮件分隔符的结尾)
  • 如果需要的话,可以用一个更复杂的email regex来代替email matcher
  • 现在到后面的大了望台``(?<;=(?
  • 第一部分(?<!X-)To:\s*To:匹配,只要它前面没有Xsomething,正如负lookback (?<!X-)所断言的那样
  • 非捕获组(?:[^@\s]+@[^\,\s]+,\s*)*?根据需要匹配表达式[^@\s]+@[^\,\s]+,\s**?量词,以允许lookback后面的内容匹配。这是一个“电子邮件跳过器”,让我们逐步跳过越来越多的电子邮件与每一场比赛
  • [^@\s]+@[^\,\s]+,\s*只是一封简陋的电子邮件,后跟一个coma和可选的空格字符(\s不仅匹配空格,还匹配回车符、制表符等)

您误解了character类的作用;您的模式匹配任何字符串包含To:或空格字符。你知道吗

这是因为[To:\s]模型是一个字符类,集合中的任何一个字符都将匹配。这就是为什么From:行匹配;:d之间的空格在这里就足够了。你知道吗

如果需要验证整个头文件名,请将匹配项锚定到^行的开头,但删除该字符类:

r'^To:\s+[\w\.-]+@[\w\.-]+'

现在,To:部分仅在行首匹配,前提是使用re.MULTILINE标志:

>>> import re
>>> text = '''\
... Date: Wed, 6 Dec 2000 02:03:00 -0800 (PST)
... From: donald.herrick@enron.com
... To: brianherrick@email.msn.com, herriceu2@tdprs.state.tx.us, 
...     robertherrick@bankunited.com, kristi.demaiolo@enron.com, 
...     suresh.raghavan@enron.com, harry.arora@enron.com
... Subject: FW: If Santa Answered his mail...
... Mime-Version: 1.0
... Content-Type: text/plain; charset=us-ascii
... Content-Transfer-Encoding: 7bit
... X-From: Donald W Herrick
... X-To: brianherrick@email.msn.com, HERRICEU2@tdprs.state.tx.us, RobertHerrick@bankunited.com, Kristi Demaiolo, Suresh Raghavan, Harry Arora
... X-cc: 
... X-bcc: 
... '''
>>> re.findall(r'^To:\s+[\w\.-]+@[\w\.-]+', text)
[]
>>> re.findall(r'^To:\s+[\w\.-]+@[\w\.-]+', text, flags=re.M)
['To: brianherrick@email.msn.com']

这只能与第一个电子邮件地址匹配,并且仅当它不包含全名之类的内容时(例如Brian Herrick <brianherrick@email.msn.com>)。你知道吗

您必须匹配整个标题

re.findall(r'^To:\s+((?:.*(?:\n[ \t]+)?)*)', text, flags=re.M)

它匹配To:头,后跟任意数量的头续行(以空格开始):

>>> re.findall(r'^To:\s+((?:.*(?:\n[ \t]+)?)*)', text, flags=re.M)
['brianherrick@email.msn.com, herriceu2@tdprs.state.tx.us, \n    robertherrick@bankunited.com, kristi.demaiolo@enron.com, \n    suresh.raghavan@enron.com, harry.arora@enron.com']

你必须把电子邮件地址从中分离出来。你知道吗

就我个人而言,我会研究^{} package,相反,它会使抓取标题更容易:

import email

message = email.message_from_string(text)
to_headers = message.get_all('to')
addresses = email.utils.getaddresses(to_headers)

演示:

>>> import email
>>> m = email.message_from_string(text)
>>> m.get_all('to')
['brianherrick@email.msn.com, herriceu2@tdprs.state.tx.us, \n    robertherrick@bankunited.com, kristi.demaiolo@enron.com, \n    suresh.raghavan@enron.com, harry.arora@enron.com']
>>> email.utils.getaddresses(m.get_all('to'))
[('', 'brianherrick@email.msn.com'), ('', 'herriceu2@tdprs.state.tx.us'), ('', 'robertherrick@bankunited.com'), ('', 'kristi.demaiolo@enron.com'), ('', 'suresh.raghavan@enron.com'), ('', 'harry.arora@enron.com')]

现在你有了所有的电子邮件地址。你知道吗

在使用正则表达式时也可以应用^{} function

>>> email.utils.getaddresses(re.findall(r'^To:\s+((?:.*(?:\n[ \t]+)?)*)', text, flags=re.M))
[('', 'brianherrick@email.msn.com'), ('', 'herriceu2@tdprs.state.tx.us'), ('', 'robertherrick@bankunited.com'), ('', 'kristi.demaiolo@enron.com'), ('', 'suresh.raghavan@enron.com'), ('', 'harry.arora@enron.com')]

作为@MartijnPieters答案的补充,regex可能不是适合这项工作的合适工具。要分析电子邮件,建议使用email.parser

>>> from email.parser import Parser
>>> headers = Parser().parsestr(email_str)
>>> pprint.pprint(map(str.strip, headers['to'].split()))
['brianherrick@email.msn.com,',
 'herriceu2@tdprs.state.tx.us,',
 'robertherrick@bankunited.com,',
 'kristi.demaiolo@enron.com,',
 'suresh.raghavan@enron.com,',
 'harry.arora@enron.com']

相关问题 更多 >