Поиск строки в списке в Python - PullRequest
1 голос
/ 06 мая 2011

Здравствуйте, у меня есть строка, содержащая адрес электронной почты.Например (user@foo.bar.com). И у меня есть список, который содержит только домены ('bar.com', 'stackoverflow.com') и т. Д.домен моей строки.Прямо сейчас я использую такой код:

if tokens[1].partition("@")[2] in domainlist:

tokens [1] содержит адрес электронной почты, а список доменов содержит домены.Но, как вы видите, результат tokens[1].partition("@")[2] вернет foo.bar.com, но в моем списке есть домен bar.com.Как я могу сделать это, если утверждение вернет true?И это должно быть очень быстро, потому что каждую секунду будут приходить сотни почтовых адресов

Ответы [ 5 ]

4 голосов
/ 06 мая 2011

Должно работать так:

if any(tokens[1].endswith(domain) for domain in domainlist): 
2 голосов
/ 06 мая 2011

Если скорость действительно важна для вас, вы можете посмотреть на такие методы, как Aho-Corasick.Доступно множество реализаций, таких как esmre / esm http://code.google.com/p/esmre/

Как указывает @Riccardo Galli, простое сопоставление строк приведет к некоторым ложным срабатываниям, поэтому сначала вы можете попробовать esmre, добавив соответствующие регулярные выражения в индекс, что-то вроде index.enter("(^|\.){0}$".format(domain))

1 голос
/ 06 мая 2011

В отличие от других ответов, здесь «foo.com» также не будет соответствовать «@ y.afoo.com»

def mailInDomains(mail,domains):

    for domain in domainList:
        dLen = len(domain)
        if mail[-dLen:]==domain and mail[-dLen-1] in ('.','@'):
            return True

    return False
1 голос
/ 06 мая 2011

Сотни почтовых адресов не должны быть проблемой. Ниже приводится одна строка:

any(domain.endswith(d) for d in MY_DOMAINS)

Здесь вы можете сделать user,sep,domain = address.rpartition('@'). В противном случае ваш текущий метод не будет работать для адресов электронной почты, таких как "B@tm4n"@something.com, которые действительны в соответствии с http://tools.ietf.org/html/rfc5322

Если производительность становится фактором, вы можете использовать Trie (разновидность структуры данных). Если производительность по-прежнему является фактором, вы можете использовать другие приемы.

Вышеприведенное относится к каждому элементу проверяемых доменов, поэтому, если в вашем списке 1000 доменов, вам нужно выполнить 1000 поисков для каждого адреса электронной почты. Если это проблема, вы можете сделать это для достижения O(1) за поиск (вы также, вероятно, хотите убедиться, что вы проверяете не более 5 суффиксов, чтобы защитить себя от злонамеренно созданных адресов электронной почты).

MY_DOMAINS = set(MY_DOMAINS)

def suffixes(domain):
    """
        suffixes('foo.bar.com') -yields-> ['foo.bar.com', 'bar.com', 'com']
    """
    while True:
        yield domain
        parts = domain.split('.',1)
        if len(parts>1)
            domain = parts[1]
        else:
            break
def isInList(address):
    user,sep,domain = address.rpartition('@')
    return any(suffix in MY_DOMAINS for suffix in suffixes(domain))
1 голос
/ 06 мая 2011

Сначала сделайте domainlist набор. Будет быстрее проверить, есть ли в нем что-то.

Во-вторых, добавьте в этот набор все «супердомены», например, «bar.com» для «foo.bar.com».

domainlist = ['foo.bar.com', 'bar2.com', 'foo3.bar3.foobar.com']
domainset = set()
for domain in domainlist:
    parts = domain.split('.')
    domainset.update('.'.join(parts[i:]) for i in xrange(len(parts)-1))

#domainset is now:
set(['bar.com',
     'bar2.com',
     'bar3.foobar.com',
     'foo.bar.com',
     'foo3.bar3.foobar.com',
     'foobar.com'])

А теперь вы можете проверить

if tokens[1].partition("@")[2] in domainset:
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...