如何检查字符串中是否包含不在列表中的字符?

4

我有一个问题。如何检查Python字符串中是否包含不在给定列表中的字符?

这是给定的列表(集合):

set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._")

3
将字符串转换为“集合(set)”,然后获取两个集合的差异。如果这个差异不为空,则说明字符串中包含集合中没有的字符。 - Barmar
为什么这个问题被关闭并标注“更新问题,使其只关注一个问题”?第二个问题在哪里?正如答案所示,这个问题显然很清楚。请重新开放。 - thebjorn
4个回答

5

当我需要验证字符串时,我通常使用正则表达式。

要创建一个集合,你需要将所有字符放在[]中。 如果想检查字符串是否包含任何不在集合中的字符,则在开头添加^。 如果要检查字符串是否包含一个或多个集合成员,则在末尾添加+

根据这些信息,检查一个字符串是否包含任何不是{a,b,c,d}中字符的正则表达式如下:

[^abcd]+(注意大小写敏感)

在Python中使用正则表达式,需要import rere.search(pattern, string, flags=0)方法会在整个字符串中查找给定的模式。

有关Python中正则表达式的更多信息可以在此处找到。可以在此处找到一个简单的正则表达式测试器。


3
您希望测试字符串中的字符是否不是给定字符集的子集。在Python中,这很简单,因为<=运算符可以测试一个集合是否是另一个集合的子集。
import string

# don't use a mutable set for this purpose
GIVEN = frozenset(string.ascii_letters + string.digits + '-._')

def uses_other_chars(s, given=GIVEN):
    return not set(s) <= given

示例:

>>> uses_other_chars('abc')
False
>>> uses_other_chars('Hello!')
True

1
还有一个set.issuperset,它可以接受任何可迭代对象。 - Kelly Bundy
1
算了。我以为它会更快,因为它可以在第一个非成员处停止而不是先将整个s创建为集合,但是我刚刚检查过了,它仍然会这样做。烦死了。 - Kelly Bundy

1
  • 使用any函数来检查字符串中每个字符是否在SET中
SET = set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._")
s = "123#"
print(any(x not in SET for x in s))

1
为什么不直接使用 set(s) - SET 呢? - thebjorn
你只需要知道你的字符串是否包含不在S中的字符。使用任何可以帮助提前停止。 - Poojan
@thebjorn 这取决于字符串。你的方法总是构建整个集合,而 any 在第一个非成员处停止。所以对于 s =“#123456789”,你的方法会更慢。也许 SET.issuperset(s) 是最好的选择。 - Kelly Bundy
@HeapOverflow 你说得很正确啊;-)。看看我的答案,进行比较(正则表达式似乎是最好的选择..)-- 哎呀,我还没来得及发表我的答案,问题就被关闭了,但最快的方法是 re.compile(r"[^-._\w\d]") - thebjorn
1
@thebjorn,这似乎确实是最快的方法。也可以使用r"[^-.\w]",因为\w包括数字和下划线。 - Kelly Bundy
显示剩余2条评论

1
比较不同解决方案的运行时间:
import timeit

search_strings = [
    '"#12"',                     # short string, early match
    '"#1234567"',                # longer string, early match
    '"1234567#"',                # longer string, late match
    '"123" * 100 + "#"',         # long string, late match
    '"123#" * 100',              # long string early match
]

algorithms = [
    ("r.search(s)", 's={};import re; r = re.compile(r"[^-.\w]")'),
    ("set(s) - SET", 's={};SET=frozenset("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._")'),
    ("any(x not in SET for x in s)", 's={};SET=frozenset("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._")'),
    ("SET.issuperset(s)", 's={};SET=frozenset("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._")'),
]

for alg, setup in algorithms:
    print alg
    for sstr in search_strings:
        print "%35s %.3f" % (sstr[:35], timeit.timeit(alg, setup.format(sstr)))

在我的电脑上运行后,会得到以下输出:

r.search(s)
                              "#12" 0.470
                         "#1234567" 0.514
                         "1234567#" 0.572
                  "123" * 100 + "#" 3.493
                       "123#" * 100 0.502
set(s) - SET
                              "#12" 0.566
                         "#1234567" 1.045
                         "1234567#" 1.075
                  "123" * 100 + "#" 7.658
                       "123#" * 100 10.170
any(x not in SET for x in s)
                              "#12" 0.786
                         "#1234567" 0.797
                         "1234567#" 1.475
                  "123" * 100 + "#" 27.266
                       "123#" * 100 1.087
SET.issuperset(s)
                              "#12" 0.466
                         "#1234567" 0.864
                         "1234567#" 0.896
                  "123" * 100 + "#" 7.512
                       "123#" * 100 10.199

我们可以看到,正则表达式的解决方案是最快的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接