【问题标题】:How can I make the output return False if a character in the string appears three times in a row?如果字符串中的字符连续出现 3 次,如何使输出返回 False?
【发布时间】:2022-01-01 06:03:37
【问题描述】:

所以我创建了这段代码,它接受一个列表并根据它们是否满足这些条件返回 True 或 False。这是我的代码

def passwordlength(password: str):
    upper = digit = special = False
    for char in password:
        if char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" :
            upper = True
        elif char in "1234567890":
            digit = True
        elif char in "$#@%!":
            special = True
    return upper and digit and special

def passwordOK(password: str):
    if passwordlength(password):
        if not (6 < len(password) < 12):
            return False
        else:
            return True
    return False

现在我想添加一个新的转折点,即如果列表中的任何字母、数字、字符连续出现 3 次,结果将返回 False.. 这是我的尝试...

    def passwordlength(password: str):
    upper = digit = special = False
    for char in password:
        if char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" :
            upper = True
        elif char in "1234567890":
            digit = True
        elif char in "$#@%!":
            special = True
    return upper and digit and special

def passwordOK(password: str):
    if passwordlength(password):
        if not (6 < len(password) < 12):
            return False
        for char in password:
            if password.count(char) > 3:
                return False
        return True
    return False

但是,这显然根本不起作用..我在这里做错了什么? 我的代码应该是什么才能使我的输出正确??

【问题讨论】:

  • 想想你将如何在纸上做到这一点。你会跟踪你读过的前一个字符;如果下一个字符相同,那么您将设置一个心理“标志”,指示如果下一个字符也相同,则连续有 3 个相同字符。这种想法应该很容易转化为代码。如果您将来遇到类似的事情,请意识到代码是将逻辑和结构化思维转移到计算机中的一种方式。所以,如果你能推理出一个任务,你就可以把它写成代码。

标签: python list tuples


【解决方案1】:

如果你想return false当一个字符,数字在字符串中出现3次,显然你应该像这样改变你的if条件:

[...]
for char in password:
    if password.count(char) == 3:
        return False
[...]

如果您的意思是至少出现 3 次:

[...]
for char in password:
    if password.count(char) >= 3:
        return False
[...]

但是password.count(char) 会为每个char 循环整个password,所以我们为什么不循环一次,然后得到结果:

[...]
from collections import defaultdict
defdict = defaultdict(lambda: 0)
for char in password:
    defdict[char] += 1
    if defdict[char] >= 3:
        return false
[...]

更新:

根据您的评论:

顺便说一句,我的意思是连续 3 次,比如如果它的 AAA、BBB、CCC 那么它应该返回 false.. 如果是 ABANA.. 那么没关系

定义一个这样的函数:

def has_3consecutive_char(password: str) -> bool:
    from collections import defaultdict
    defdict = defaultdict(lambda: 0)
    prev_char = ""
    for char in password:
        if prev_char == char:
            defdict[char] += 1
            if defdict[char] >= 2:
                return True
        else:
            defdict[char] = 0
        prev_char = char
    return False

然后在你的 passwordOK 函数中使用它:

def passwordOK(password: str):
    if passwordlength(password):
        if not (6 < len(password) < 12):
            return False
        if has_3consecutive_char(password):
                return False
        return True
    return False

【讨论】:

  • 我的意思是连续 3 次,比如如果它的 AAA、BBB、CCC 那么它应该返回 false.. 如果它是 ABANA.. 那么没关系
  • 感谢您的评论@JoshuaBradley。我已根据您的评论更新了我的答案。
  • 我再次更新了它@JoshuaBradley 请检查一下。这将工作 100%
【解决方案2】:

使用itertools 中的groupby。在此版本中,您可以设置一行中的字符数。

from itertools import groupby

def passwordinarow(password: str, n: int=3):
    """Return True if password contains 'n' characters in a row else False."""
    return any([len(list(g)) >= n for c, g in groupby(password)])

测试:

>>> passwordinarow('AAABC123$')
True

>>> passwordinarow('ABC123$')
False

【讨论】:

    【解决方案3】:

    有很多不同的方法可以解决这个问题。

    我个人可能会这样做:

    def has_repeated_chars(password: str, n_repetitions: int=3) -> bool:
        ngrams = zip(*(password[i] for i in range(n_repetitions)))
        return min(len(set(trigram)) for trigram in ngrams) == 1
    

    一般逻辑是创建一个长度为 3 的 ngram 的可迭代对象,为每个 ngram 创建一个集合,如果该集合的长度为 1,那么我们知道同一个字符已重复 3 次。

    【讨论】:

    • 虽然这行得通,但我认为当所有内容都没有注释并压缩成两条像这样塞满的行时,初学者很难理解发生了什么。我认为将其分解为单独的行,并让 cmets 解释所有内容,对于 Python 专家以外的任何人都需要了解这里发生了什么。
    猜你喜欢
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-22
    • 1970-01-01
    • 2021-01-27
    相关资源
    最近更新 更多