对 python 中正则表达式匹配的唯一值进行排序

Sorting the unique values from regex match in python

我正在尝试解析日志文件以提取电子邮件地址。 我能够匹配电子邮件并在正则表达式的帮助下打印它。 我注意到我的日志文件中有几封重复的电子邮件。你能帮我弄清楚如何删除重复项并仅打印基于匹配模式的唯一电子邮件地址吗?

这是我到目前为止编写的代码:

import sys
import re

file = open('/Users/me/Desktop/test.txt', 'r')
temp =[]
for line in file.readlines():
    if '->' in line:
        temp = line.split('->')
    elif '=>' in line:
        temp = line.split('=>')

    if temp:
        #temp[1].strip()
        pattern = re.match('^\x20\w{1,}@\w{1,}\.\w{2,3}\x20?', str(temp[1]), re.M)
        if pattern is not None:
            print pattern.group()

        else:
            print "nono"

这是我尝试解析的示例日志文件:

Feb 24 00:00:23 smtp1.mail.net exim[5660]: 2014-02-24 00:00:23 1Wuniq-mail-idSo-Fg -> someuser@somedomain.com R=mail T=remote_smtp H=smtp.mail.net [000.00.34.17]

Feb 24 00:00:23 smtp1.mail.net exim[5660]: 2014-02-24 00:00:23 1Wuniq-mail-idSo-Fg -> someuser@somedomain.com R=mail T=remote_smtp H=smtp.mail.net [000.00.34.17]

Feb 24 00:00:23 smtp1.mail.net exim[5661]: 2014-02-24 00:00:23 1Wuniq-mail-idSm-1h => someuser@somedomain.com R=mail T=pop_mail_net H=mta.mail.net [000.00.34.6]

Feb 24 00:00:23 smtp1.mail.net exim[5661]: 2014-02-24 00:00:23 1Wuniq-mail-idSm-1h => me@somedomain.com R=mail T=pop_mail_net H=mta.mail.net [000.00.34.6]

Feb 24 00:00:23 smtp1.mail.net exim[5661]: 2014-02-24 00:00:23 1Wuniq-mail-idSm-1h => wo@somedomain.com R=mail T=pop_mail_net H=mta.mail.net [000.00.34.6]

Feb 24 00:00:23 smtp1.mail.net exim[5661]: 2014-02-24 00:00:23 1Wuniq-mail-idSm-1h => lol@somedomain.com R=mail T=pop_mail_net H=mta.mail.net [000.00.34.6]

Feb 24 00:00:23 smtp1.mail.net exim[5661]: 2014-02-24 00:00:23 1Wuniq-mail-idSm-1h Completed

另外,我很好奇我是否可以改进我的程序或正则表达式。任何建议都会很有帮助。

提前致谢。

您可以使用 set 容器来保留唯一的结果,并且每次您想要打印匹配的电子邮件时,您可以检查它是否不存在于您的集合中并打印它:

import sys
import re

file = open('/Users/me/Desktop/test.txt', 'r')
temp =[]
seen = set()
for line in file.readlines():
    if '->' in line:
        temp = line.split('->')
    elif '=>' in line:
        temp = line.split('=>')

    if temp:
        #temp[1].strip()
        pattern = re.match('^\x20\w{1,}@\w{1,}\.\w{2,3}\x20?', str(temp[1]), re.M)
        if pattern is not None:
            matched =  pattern.group()
            if matched not in seen:
               print matched 

        else:
            print "nono"

因为 danidee (he was first) said, set 可以做到这一点

试试这个:

from __future__ import print_function

import re

with open('test.txt') as f:
    data = f.read().splitlines()

emails = set(re.sub(r'^.*\s+(\w+\@[^\s]*?)\s+.*', r'', line) for line in data if '@' in line)

print('\n'.join(emails)) if len(emails) else print('nono')

输出:

lol@somedomain.com
me@somedomain.com
someuser@somedomain.com
wo@somedomain.com

PS 你可能想做一个适当的电子邮件正则表达式检查,因为我使用了非常原始的检查

一些重复是由于您的代码中的一个错误,您在处理每一行时没有重置 temp 包含 ->=> 且前面的行 包含以下任一行这些字符串将触发 if temp: 测试,并输出上一行的电子邮件地址(如果有的话)。

当该行既不包含 -> 也不包含 =>.

时,可以通过使用 continue 跳回到循环开头来解决这个问题

对于由于同一电子邮件地址出现在多行中而出现的其他真正的重复,您可以使用 set 将其过滤掉。

import sys
import re

addresses = set()
pattern = re.compile('^\x20\w{1,}@\w{1,}\.\w{2,3}\x20?')

with open('/Users/me/Desktop/test.txt', 'r') as f:
    for line in f:
        if '->' in line:
            temp = line.split('->')
        elif '=>' in line:
            temp = line.split('=>')
        else:
            # neither '=>' nor '->' present in the line
            continue

        match = pattern.match(temp[1])
        if match is not None:
            addresses.add(match.group())
        else:
            print "nono"

for address in sorted(addresses):
    print(address)

地址存储在一组中以删除重复项。然后将它们分类并打印。另请注意使用 with 语句在上下文管理器中打开文件。这保证文件将始终关闭。

此外,由于您将多次应用相同的正则表达式模式,因此值得提前编译以提高效率。

使用正确编写的正则表达式模式可以大大简化您的代码:

import re

addresses = set()
pattern = re.compile(r'[-=]> +(\w{1,}@\w{1,}\.\w{2,3})')

with open('test.txt', 'r') as f:
    for line in f:
        match = pattern.search(line)
        if match:
            addresses.add(match.groups()[0])

for address in sorted(addresses):
    print(address)