检查特定字符是否在字符串中

Check if specific characters are in a string

我需要查找并计算可以在一个字符串中找到多少个字符。我把字符分为chars1[a:m]和chars2[n:z],有两个计数器。

输出应该是0/14,但实际上是0/1。我认为它只检查是否包含一个且只有一个项目,然后退出循环。是这样吗?

这是代码。

string_1 = "aaabbbbhaijjjm"

def error_printer(s):
    chars1 = "abcdefghijklm"
    chars2 = "nopqrstuvwxyz"
    counter1 = 0
    counter2 = 0

    if ((c in s) for c in chars1):
        counter1 += 1
    elif ((c in s) for c in chars2):
        counter2 += 1
    print(str(counter2) + "/" + str(counter1))

error_printer(string_1)

chars1/chars2 中出现在 s

中的字符数

这是有道理的,因为您 if 条件 递增。由于 if 而不是 在循环中,您可以将其递增一次。

现在我们可以展开生成器进入for循环。这将解决问题的一部分,并且 生成 0/6:

<b>for c in chars1:
    if c in s:
        counter1 += 1</b>
<b>for c in chars2:
    if c in s:</b>
        counter2 += 1

尽管如此,这仍然不会非常有效:它需要 O(n) 最坏情况来检查字符是否在字符串中。您可以先用字符串中的字符构造一个 set,然后执行查找(通常是 O(1) 平均情况:

def error_printer(s):
    <b>sset = set(s)</b>
    chars1 = "abcdefghijklm"
    chars2 = "nopqrstuvwxyz"
    counter1 = 0
    counter2 = 0
    for c in chars1:
        if c in <b>sset</b>:
            counter1 += 1
    for c in chars2:
        if c in <b>sset</b>:
            counter2 += 1
    print(str(counter2) + "/" + str(counter1))

现在效率提高了,但还是不够优雅:代码量大,而且还得看代码才能知道是干什么的。我们可以使用 sum(..) 构造来计算满足特定约束的元素数量,例如:

def error_printer(s):
    sset = set(s)
    chars1 = "abcdefghijklm"
    chars2 = "nopqrstuvwxyz"
    <b>counter1 = sum(c in sset for c in chars1)
    counter2 = sum(c in sset for c in chars2)</b>
    print(str(counter2) + "/" + str(counter1))

这会产生 0/6,因为 [A-M] 范围内有六个字符出现在 s 中,而 [N-Z] 范围内有 0 个字符出现在 s.

s 中出现在 char1/char2

中的字符数

然而,根据问题的正文,您想 计算 s 中出现在两个不同范围 .[=42= 中的字符数]

另一个相关问题是计算 char1/char2 中出现的字符数。在那种情况下,我们只需 交换循环 :

def error_printer(s):
    chars1 = <b>set(</b>"abcdefghijklm"<b>)</b>
    chars2 = <b>set(</b>"nopqrstuvwxyz"<b>)</b>
    counter1 = sum(c in <b>chars1</b> for c in <b>s</b>)
    counter2 = sum(c in <b>chars2</b> for c in <b>s</b>)
    print(str(counter2) + "/" + str(counter1))

这会产生 0/14,因为 s 中有 14 个字符出现在 [A-M] 范围内(如果 'a's 中出现两次,则我们计算了两次),并且 s 中的 none 个字符出现在 [N-Z] 范围内。

使用范围检查

由于我们正在使用 范围,我们可以使用比较而不是元素检查,并通过两次比较检查使其 运行,例如:

def error_printer(s):
    counter1 = sum(<b>'a' <= c <= 'm'</b> for c in s)
    counter2 = sum(<b>'n' <= c <= 'z'</b> for c in s)
    print(str(counter2) + "/" + str(counter1))

尝试使用 if 条件递增,对 s 进行一次循环。

for c in s:
    if c in char1:
        counter1 += 1
    if c in char2:
        counter2 += 1

一个 for 循环遍历 s 两个计数器:

string_1 = "aaabbbbhaijjjm"

def error_printer(s):
    chars1 = "abcdefghijklm"
    chars2 = "nopqrstuvwxyz"
    counter1 = 0
    counter2 = 0
    for c in s:
        if c in chars1:
            counter1 += 1
        if c in chars2:
            counter2 += 1
    print(str(counter2) + "/" + str(counter1))

error_printer(string_1)

for 循环的替代方法:

string_1 = "aaabbbbhaijjjm"

def error_printer(s):
    chars1 = "abcdefghijklm"
    chars2 = "nopqrstuvwxyz"

    counter1 = sum(s.count(c) for c in chars1)
    counter2 = sum(s.count(c) for c in chars2)

    print(str(counter2) + "/" + str(counter1))

error_printer(string_1)

你数一下"a""b""c"...在字符串输入中显示了多少次,然后你总结一下。

它仍然效率低下,但利用了 string.countsum 函数,使其更容易阅读和理解正在发生的事情。

您可以将 collections.Countersum 结合使用:

from collections import Counter

def error_printer(s):
    cnts = Counter(s)
    chars1 = "abcdefghijklm"
    chars2 = "nopqrstuvwxyz"
    print(sum(cnts[c] for c in chars2), '/', sum(cnts[c] for c in chars1))

>>> error_printer("aaabbbbhaijjjm")
0 / 14

正如已经建议的那样,for 循环是可行的方法。您使用生成器表达式作为 if 语句的布尔值,它只会 运行 一次。第一个表达式被计算 True,但这不会使它 运行 包含的代码不止一次。因为第一个 if 做了 运行,然而,elif 甚至从来没有计算过它的条件。这就是为什么你想要 for 循环,但你不应该循环 char1 和 char2,你想循环 s:

for c in s:
    if c in char1:
        counter1 += 1
    if c in char2:
        counter2 += 1
print(str(counter2) + "/" + str(counter1))

这为我们指出了一些更巧妙的方法,首先是使用 c in charX 作为迭代器:

for c in s:
    counter1 += c in char1
    counter2 += c in char2

现在有点不太清楚了,但我们可以通过添加第二个 for 循环使其更加清晰:

char = [‘abcdefghijklm’,’nopqrstuvwxyz’]
counter = [0,0]
for c in s:
    for i in [0,1]:
        counter[i] += c in char[i]

这可能有点过头了,但我希望它能帮助您了解如何在 python 中重新排列这些内容!

(根据以下评论进行编辑)