【问题标题】:Searching a string in a list in python在python的列表中搜索字符串
【发布时间】:2011-08-19 23:22:57
【问题描述】:

你好 我有一个包含邮件地址的字符串。例如(user@foo.bar.com) 我有一个列表,其中仅包含域('bar.com'、'stackoverflow.com')等。

如果列表包含我的字符串的域,我想搜索它。现在我正在使用这样的代码

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

tokens[1] 包含邮件地址, domainlist 包含域。 但正如您所见,tokens[1].partition("@")[2] 的结果将返回foo.bar.com,但我的列表包含域bar.com。 如何使这个 if 语句返回 true?而且速度应该非常快,因为每秒会收到数百个邮件地址

【问题讨论】:

标签: python string list substring


【解决方案1】:

它应该像这样工作:

if any(tokens[1].endswith(domain) for domain in domainlist): 

【讨论】:

  • 太简单了,域名 'foo.com' 也会匹配 'somefoo.com'
  • 哎呀,对不起......它有一个问题......如果'bar.com'在域列表中,它会为'me@foobar.com'返回true。可能不是 OP 想要的... :-(
  • 请参阅stackoverflow.com/questions/5908190/… 以防len(domainlist)>1000,以了解避免做 1000 倍工作的方法。否则这是一个有效的答案。
【解决方案2】:

如果速度对您来说真的是个问题,您可以研究像 Aho-Corasick 这样的方法。有很多可用的实现,比如esmre/esmhttp://code.google.com/p/esmre/

正如@Riccardo Galli 所指出的,简单的字符串匹配会产生一些误报,因此您可以先尝试使用esmre,将相应的正则表达式添加到索引中,例如index.enter("(^|\.){0}$".format(domain))

【讨论】:

    【解决方案3】:

    与其他答案相反,这里的“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
    

    【讨论】:

      【解决方案4】:

      首先,将domainlist 设为一组。检查里面是否有东西会更快。

      其次,将所有“超级域”添加到该集合中,例如“foo.bar.com”的“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:
      

      【讨论】:

        【解决方案5】:

        数百个邮件地址应该不是问题。以下为单行:

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

        在这里,你可以做user,sep,domain = address.rpartition('@')。否则,对于"B@tm4n"@something.com等电子邮件地址,您当前的方法将失败,根据https://www.rfc-editor.org/rfc/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))
        

        【讨论】:

          猜你喜欢
          • 2020-03-12
          • 2016-04-20
          • 2016-04-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-09-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多