【问题标题】:Test if string ONLY contains given characters测试字符串是否仅包含给定字符
【发布时间】:2013-09-09 09:12:26
【问题描述】:

在 Python 中检查字符串是否仅包含某些指定字符的最简单方法是什么? (当然不使用 RegEx 或任何东西)

具体来说,我有一个字符串列表,我想过滤掉所有字符串,除了仅由另一个字符串中的任何字母组成的单词。例如,过滤['aba', 'acba', 'caz'] 虽然'abc' 应该给出['aba', 'acba']。 (z不在abc)

就像只保留可以使用给定字母制作的物品一样。

【问题讨论】:

  • 您要返回“acb”还是“acba”?
  • 您尝试实现什么?鉴于没有 RegEx 的条件,它看起来非常像家庭作业。
  • 正则表达式有什么问题?那将是一条非常微不足道的线...
  • @Joseph 你是什么意思?列表中的第二项是'acba',在预期的输出中它减少到只是'acb'?
  • 是的,我希望它返回 acdacba。不,这实际上不是家庭作业,我正在编写一个程序来计算可以由受约束的字符组成的英语单词的数量。但是,是的,我是菜鸟。

标签: python string


【解决方案1】:

假设您的示例中的差异是一个错字,那么这应该有效:

my_list = ['aba', 'acba', 'caz']
result = [s for s in my_list if not s.strip('abc')]

结果为@​​987654323@。如果要剥离的字符串在输入中只包含字符,string.strip(characters) 将返回一个空字符串。字符顺序无关紧要。

【讨论】:

    【解决方案2】:

    您可以使用sets:

    >>> l = ['aba', 'acba', 'caz']
    >>> s = set('abc')
    >>> [item for item in l if not set(item).difference(s)]
    ['aba', 'acba']
    

    【讨论】:

    • @Bakuriu +1 是的 - 如果你已经有一个集合,请使用适当的方法,而不是将另一个项目转换为集合并提供现有集合:)
    • 嗯。我突然想到symmetric_difference 不会这样做。因为当且仅当item 包含完全s(set('abc').symmetric_difference('aba') -> {'c'}) 相同的元素时,它才匹配。虽然我们希望item 成为元素的subset,所以s.issuperset(item) 应该这样做。 :s
    • @Bakuriu 您对frozenset 的评论是正确的,经过测试并看到frozenset 在这里速度较慢。谢谢。
    • @alecxe 我相信 CPython 对 setfrozensets 的实现基本相同(例如,有创建新 set 的常用函数,更新它等参见 Objects/setobject.c 文件在来源)。 frozensets 根本不提供有副作用的方法。我删除了那条评论,因为其余的都是错误的。
    【解决方案3】:

    假设您只想要列表中只有搜索字符串中的字符的字符串,您可以轻松执行

    >>> hay = ['aba', 'acba', 'caz']
    >>> needle = set('abc')
    >>> [h for h in hay if not set(h) - needle]
    ['aba', 'acba']
    

    如果你不想避免设置,你也可以使用str.translate 来做同样的事情。在这种情况下,您将删除搜索字符串中的所有字符。

    >>> needle = 'abc'
    >>> [h for h in hay if not h.translate(None,needle)]
    ['aba', 'acba']
    

    【讨论】:

      【解决方案4】:

      类似这样的:

      strings = ['aba', 'acba', 'caz']
      given = "abc"
      filter(lambda string: all(char in given for char in string), strings)
      

      【讨论】:

        【解决方案5】:

        关于重新使用基本字符串中的字母,这个问题有些模棱两可。或者是否应该或不应该重复,或者允许缺少字母。该解决方案通过包含reuse 参数的函数解决了这个问题:

        from collections import Counter
        
        def anagram_filter(data, base, reuse=True):
            if reuse: # all characters in objects in data are in base, count ignored
                base = set(base)
                return [d for d in data if not set(d).difference(base)]
            r = []
            cb = Counter(base)
            for d in data:
                for k, v in Counter(d).iteritems():
                    if (k not in cb.keys()) or (v > cb[k]):
                        break
                else:
                    r.append(d)
            return r
        

        用法:

        >>> anagram_filter(['aba', 'acba', 'caz'], 'abc')
        ['aba', 'acba']
        >>> anagram_filter(['aba', 'acba', 'caz'], 'abc', False)
        []
        >>> anagram_filter(['aba', 'cba', 'caz'], 'abc', False)
        ['cba']
        

        【讨论】:

          【解决方案6】:

          下面是代码:

          a = ['aba', 'acba', 'caz']
          needle = 'abc'
          
          def onlyNeedle(word):
              for letter in word:
                  if letter not in needle:
                      return False
          
              return True
          
          a = filter(onlyNeedle, a)
          
          print a
          

          【讨论】:

            【解决方案7】:

            我认为你不愿意使用正则表达式并不是一个真正的问题:

            strings = ['aba', 'acba', 'caz']
            given = "abc"
            filter(lambda value: re.match("^[" + given + "]$", value), strings)
            

            【讨论】:

            • re.escape(given) 会更安全。
            • @Paco :of course 部分可能表示对固有复杂性的偏见。我认为这种偏见应该得到纠正。因此我的假设。当然,我可能是错的,但我试图表明 RegEx or anything 简单而友好。
            猜你喜欢
            • 1970-01-01
            • 2011-03-18
            • 1970-01-01
            • 2017-04-27
            • 1970-01-01
            • 2018-08-11
            • 2020-11-03
            • 2011-02-11
            • 1970-01-01
            相关资源
            最近更新 更多