Python 正则表达式匹配字母表中的 3 个连续字符,但不一定并排

Python regex to match 3 consecutive characters in the alphabet but not necessarily side by side

我必须构建一个 python 函数,该函数使用正则表达式来检查密码的复杂性,该密码应至少包含 8 个字符,包含数字、字母和特殊符号以及最后的规则(最难的):不是包含三个连续的字母或三个连续的数字。 为了说明最后一条规则:Mz2a%yc98B 将不被接受,因为它包含 3 个连续的字母:aBc

前两条规则我做得很好,但我不知道我能为最后一条规则做些什么。我认为这很复杂。有些人告诉我使用正则表达式不可能做到这一点,但实际上它必须是可能的,否则这很疯狂不?

非常感谢!

到目前为止我的代码:

import re

pattern = re.compile(r"")
while True:
    password = input("Enter your password")
    if re.match(r"(?=.*[a-z])(?=.*[A-Z])(?=(.*[!%@$#&^*()\-__+.]){1,})(?=.*[0-9]).{8,}", password):
        result = pattern.match(password)
        print("Your password is strong enough")
    else:
        print("Your password is not strong enough")

而且在我给出的示例密码中,是的,它们是 aBc,B 是最后一个字符。 这只是一个例子。当我指的是连续的时,我指的是字母表中的连续。例如,如果使用甚至散布在密码中的 efg 字母,它必须检测到它。 谢谢

这里是你的问题集的第三个标准的解决方案。

import string
from more_itertools import windowed

alphabet = string.ascii_lowercase
numbers = string.digits

passwords = ["Mz2a%yc98B", "a1b2g3D!", "Tr0ub4dor?"]

def find_triplets(charset: set, target: str) -> bool:
    if len(charset) < 3:
        return False
    else:
        chars = "".join(sorted(charset))
        triplets = ["".join(tpl) for tpl in windowed(chars, 3)]
        return any(triplet in target for triplet in triplets)

for pwd in passwords:
    # we use sets to get rid of duplicatess
    alpha = set()
    nums = set()
    for char in pwd:
        if char.isalpha():
            alpha.add(char.lower())
        elif char.isdigit():
            nums.add(char)
        else:
            pass # we don't care about symbols here
    if find_triplets(alpha, alphabet) or find_triplets(nums, numbers):
        print(f"Your password {pwd} contains 3 consecutive letters or numbers")
    else:
        print(f"Your password {pwd} is good enough, I guess")

在设置代码之后,我们首先定义一个函数,在输入 charset 被排序并变成字符串后,生成 3 个字符的字符串 (triplets)。这使用 windowed() function from the very helpful 3rd party more_itertools 模块。如果函数 returns True 找到与 target 字符串中的连续序列匹配的任何三元组,则函数 False 如果没有。够简单了。

接下来,我们遍历我们的密码列表(您在代码中使用了 input(),这很好)。首先,我们逐个字符地遍历密码字符串,并将它们添加到适当的集合中(在字母字符的情况下为小写)。然后我们调用我们的 find_triplets() 函数来测试字母或数字的连续运行,并相应地打印一条消息。

您显然想要更改其中的一些内容以适应您的任务,但我会把它留给您。

还有另一种使用 re.search() 的方法,但我认为 any(triplet in target for triplet in triplets) 更加 Pythonic。

你问用正则表达式可能吗?当然!漂亮吗?那是在旁观者的眼中。

您需要一个如下所示的正则表达式(设置了 case-indifferent 标志):

^(?=.*\d)(?=.*[a-z])(?=.*[<special symbols here>])(?!<no 3 digits that are consecutive>)(?!<no three letters that are consecutive>).{8}

让我们看看负面前瞻

(?!<no 3 digits that are consecutive>) 

我们可以这样写。

(?!(?:(?=.*0)(?=.*1)(?=.*2))|(?:(?=.*1)(?=.*2)(?=.*3))|(?:(?=.*2)(?=.*3)(?=.*4))|(?:(?=.*3)(?=.*4)(?=.*5))|(?:(?=.*4)(?=.*5)(?=.*6))|(?:(?=.*5)(?=.*6)(?=.*7))|(?:(?=.*6)(?=.*7)(?=.*8))|(?:(?=.*7)(?=.*9)(?=.*9)))

Demo

表达式可以写成 verbose 模式(re.Xre.VERBOSE)使其成为 self-documenting.

(?!          # begin negative lookahead       
  (?:        # begin non-capture group
    (?=.*0)  # match > 0 characters followed by 0 (positive lookahead) 
    (?=.*1)  # match > 0 characters followed by 1 
    (?=.*2)  # match > 0 characters followed by 2
  )          # end non-capture group
  |          # or
  ... similar for (?:(?=.*1)(?=.*2)(?=.*3))
  ...
)            # end negative lookahead

构建

(?!<no three letters that are consecutive>)

xyz 相似(包含 23 个元素的交替,abc ).