检查字符串是否包含列表元素

时间:2017-06-18 18:58:58

标签: python python-3.x

如何检查字符串' str1'包含列表中的元素' lis'?

str1 = "45892190"
lis = [89,90]

7 个答案:

答案 0 :(得分:2)

如果不允许重叠,这个问题就会比最初看起来困难得多。 据我所知,没有其他答案是正确的(最后见测试用例)。

需要递归,因为如果子串出现多次,则使用一次出现而不是另一次出现可能会阻止其他子串的发现。

这个答案使用了两个功能。第一个查找字符串中每个子字符串的出现,并返回字符串的迭代器,其中子字符串已被一个不应出现在任何子字符串中的字符替换。

第二个函数以递归方式检查是否有任何方法可以找到字符串中的所有数字:

def find_each_and_replace_by(string, substring, separator='x'):
    """
    list(find_each_and_replace_by('8989', '89', 'x'))
    # ['x89', '89x']
    list(find_each_and_replace_by('9999', '99', 'x'))
    # ['x99', '9x9', '99x']
    list(find_each_and_replace_by('9999', '89', 'x'))
    # []
    """
    index = 0
    while True:
        index = string.find(substring, index)
        if index == -1:
            return
        yield string[:index] + separator + string[index + len(substring):]
        index += 1


def contains_all_without_overlap(string, numbers):
    """
    contains_all_without_overlap("45892190", [89, 90])
    # True
    contains_all_without_overlap("45892190", [89, 90, 4521])
    # False
    """
    if len(numbers) == 0:
        return True
    substrings = [str(number) for number in numbers]
    substring = substrings.pop()
    return any(contains_all_without_overlap(shorter_string, substrings)
               for shorter_string in find_each_and_replace_by(string, substring, 'x'))

以下是测试用例:

tests = [
    ("45892190", [89, 90], True),
    ("8990189290", [89, 90, 8990], True),
    ("123451234", [1234, 2345], True),
    ("123451234", [2345, 1234], True),
    ("123451234", [1234, 2346], False),
    ("123451234", [2346, 1234], False),
    ("45892190", [89, 90, 4521], False),
    ("890", [89, 90], False),
    ("8989", [89, 90], False),
    ("8989", [12, 34], False)
]

for string, numbers, should in tests:
    result = contains_all_without_overlap(string, numbers)
    if result == should:
        print("Correct answer for %-12r and %-14r (%s)" % (string, numbers, result))
    else:
        print("ERROR : %r and %r should return %r, not %r" %
              (string, numbers, should, result))

和相应的输出:

Correct answer for '45892190'   and [89, 90]       (True)
Correct answer for '8990189290' and [89, 90, 8990] (True)
Correct answer for '123451234'  and [1234, 2345]   (True)
Correct answer for '123451234'  and [2345, 1234]   (True)
Correct answer for '123451234'  and [1234, 2346]   (False)
Correct answer for '123451234'  and [2346, 1234]   (False)
Correct answer for '45892190'   and [89, 90, 4521] (False)
Correct answer for '890'        and [89, 90]       (False)
Correct answer for '8989'       and [89, 90]       (False)
Correct answer for '8989'       and [12, 34]       (False)

答案 1 :(得分:2)

str1 = "45892190"
lis = [89,90]

for i in lis:
    if str(i) in str1:
        print("The value " + str(i) + " is in the list")
  

输出:

     

值89在列表中

     

值90在列表中

如果你想检查lis中的所有值是否都在str1中,那么cricket_007的代码

all(str(l) in str1 for l in lis)
out: True

是您正在寻找的

答案 2 :(得分:1)

如果您想要不重叠的匹配,我可以这样做:

  • 创建初始字符串的副本(因为我们将对其进行修改)
  • 浏览列表的每个元素,如果我们在字符串中找到元素,我们将其替换为x
  • 同时,如果我们在字符串中找到数字,我们会增加一个计数器
  • 最后,如果变量等于列表的长度,则意味着它的所有元素都在那里
str1 = "45890190"
lis1 = [89, 90]

copy, i = str1, 0
for el in lis1:
    if str(el) in copy:
        copy = copy.replace(str(el), 'x')
        i = i + 1

if i == len(lis1):
    print(True)

更多,如果我们添加一个额外的条件,我们就不需要一个计数器,当一个元素未在字符串中找到时,该条件将返回False。也就是说,我们得到以下最终解决方案:

def all_matches(_list, _string):
    str_copy = _string
    for el in _list:
        if str(el) not in str_copy:
            return False
        str_copy = str_copy.replace(str(el), 'x')
    return True

您可以通过以下方式进行测试:

str1 = "4589190"
lis1 = [89, 90]

print(all_matches(lis1, str1))

> True

这可能不是您正在寻找的最佳解决方案,但我想这符合目的。

答案 3 :(得分:0)

您可以使用all()功能

In [1]: str1 = "45892190"
   ...: lis = [89,90]
   ...: all(str(l) in str1 for l in lis)
   ...:
Out[1]: True

答案 4 :(得分:0)

def contains(s, elems):
    for elem in elems:
        index = s.find(elem)
        if index == -1:
            return False
        s = s[:index] + s[index + len(elem) + 1:]
    return True

用法:

>>> str1 = "45892190"
>>> lis = [89,90]
>>> contains(str1, (str(x) for x in lis))
True
>>> contains("890", (str(x) for x in lis))
False

答案 5 :(得分:0)

您可以使用正则表达式进行搜索。

import re
str1 = "45892190"
lis = [89,90]
for i in lis:
  x = re.search(str(i), str1)
  print(x)

答案 6 :(得分:0)

可以使用正则表达式正确实现此功能。生成输入的所有唯一排列,对于每个排列,将术语与“。*”连接,然后将所有排列与“|”连接。例如,[89,90,8990]变为89. * 8990。* 90 | 89. * 90 * 8990 | 8990. 89. * * 90 | 8990. 90. * * 89 | 90. * 89 * 8990 | 90. * 8990. * 89,我在每个“|”之后添加了一个空格为了清楚起见。“

以下内容通过Eric Duminil的测试套件。

import itertools
import re

def create_numbers_regex(numbers):
    # Convert each into a string, and double-check that it's an integer
    numbers = ["%d" % number for number in numbers]

    # Convert to unique regular expression terms
    regex_terms = set(".*".join(permutation)
                            for permutation in itertools.permutations(numbers))
    # Create the regular expression. (Sorted so the order is invariant.)
    regex = "|".join(sorted(regex_terms))
    return regex

def contains_all_without_overlap(string, numbers):
    regex = create_numbers_regex(numbers)
    pat = re.compile(regex)
    m = pat.search(string)
    if m is None:
        return False
    return True

但是,这是一个很大的问题,在最坏的情况下,正则表达式的大小会随着数字的阶乘而增长。即使只有8个唯一数字,也就是40320正则表达式。只需要几秒钟就可以编译那个正则表达式。

这个解决方案唯一有用的地方是,如果你有一些数字,并且你想要搜索很多字符串。在这种情况下,您也可以查看re2,我相信它可以处理正则表达式而无需回溯。