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

时间:2014-07-16 08:14:11

标签: 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: 

应该返回(来自" 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

(来自" X-To:"行) brianherrick@email.msn.com,HERRICEU2@tdprs.state.tx.us, RobertHerrick@bankunited.com

我当前的正则表达式是re.findall([To:\s][\w\.-]+@[\w\.-]+, text),它返回" To:"," X-To:"和"来自:"线。

我的问题:

  1. 为什么电子邮件地址位于" From:"行还回来了吗?它 与正则表达式的[To:\s]部分不匹配?!
  2. 我如何确保只有以下电子邮件地址:" To:"是 回? (也就是说,如何排除以下电子邮件地址 " X-To:"?我认为你可以使用先行断言,但我不知道该怎么做?

3 个答案:

答案 0 :(得分:2)

作为@MartijnPieters答案的附录,正则表达式可能不是JOB的正确工具。要解析电子邮件,建议使用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']

答案 1 :(得分:0)

你误解了角色课的作用;您的模式匹配任何地方字符串包含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']

并且您必须单独提取电子邮件地址。

就个人而言,我会调查email 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')]

现在您拥有所有电子邮件地址。

使用正则表达式时,也可以应用email.utils.getaddresses() 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')]

答案 2 :(得分:0)

regex模块:无限外观和其他功能

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

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

示例代码

我在Python 3.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

<强>解释

  • 我们有一个很大的lookbehind,然后是一个非常基本的电子邮件匹配器:[^@\s]+@[^\,\s]+匹配任何不是arrobas或whitespace char的字符,然后是arrobas,然后是任何不是逗号或空格char的字符(输入中的电子邮件末尾分隔符)
  • 如果需要,可以使用更复杂的电子邮件正则表达式替换该电子邮件匹配器
  • 现在看起来很大“`(?&lt; =(?
  • 第一部分(?<!X-)To:\s*To:匹配,只要它不在Xsomething之前,由负面的后方(?<!X-)声明
  • 非捕获组(?:[^@\s]+@[^\,\s]+,\s*)*?匹配表达式*?所需的少量([^@\s]+@[^\,\s]+,\s*量词),以允许lookbehind后面的内容匹配。这是一个“电子邮件浏览器”,可让我们逐步跳过越来越多的电子邮件
  • [^@\s]+@[^\,\s]+,\s*只是粗略的电子邮件,后跟昏迷和可选的空白字符(\s不仅匹配空格,还匹配回车,标签等。)