Python 计算一个字符串中同时出现多个子字符串的次数
我正在用Python编写一个简单的脚本,在评分系统上评估密码的强度,该评分系统根据密码是否包含大写或小写字母、数字和学校符号来评分 其中一个要求是,它在英国QWERTY键盘上检查从左到右连续的3个字母或数字,并为每个实例扣分5分。例如,密码“qwer123”将因“qwe”、“wer”和“123”而损失15分。如何做到这一点?我的当前代码如下Python 计算一个字符串中同时出现多个子字符串的次数,python,python-requests,Python,Python Requests,我正在用Python编写一个简单的脚本,在评分系统上评估密码的强度,该评分系统根据密码是否包含大写或小写字母、数字和学校符号来评分 其中一个要求是,它在英国QWERTY键盘上检查从左到右连续的3个字母或数字,并为每个实例扣分5分。例如,密码“qwer123”将因“qwe”、“wer”和“123”而损失15分。如何做到这一点?我的当前代码如下 def check(): user_password_score=0 password_capitals=False password_lowe
def check():
user_password_score=0
password_capitals=False
password_lowers=False
password_numbers=False
password_symbols=False
password_explanation_check=False
ascii_codes=[]
password_explanation=[]
print("The only characters allowed in the passwords are upper and lower case letters, numbers and these symbols; !, $, %, ^, &, *, (, ), _, -, = and +.\n")
user_password=str(input("Enter the password you would like to get checked: "))
print("")
if len(user_password)>24 or len(user_password)<8:
print("That password is not between 8 and 24 characters and so the Password Checker can't evaluate it.")
menu()
for i in user_password:
ascii_code=ord(i)
#print(ascii_code)
ascii_codes.append(ascii_code)
#print(ascii_codes)
for i in range(len(ascii_codes)):
if ascii_codes[i]>64 and ascii_codes[i]<90:
password_capitals=True
elif ascii_codes[i]>96 and ascii_codes[i]<123:
password_lowers=True
elif ascii_codes[i]>47 and ascii_codes[i]<58:
password_numbers=True
elif ascii_codes[i] in (33,36,37,94,38,42,40,41,45,95,61,43):
password_symbols=True
else:
print("Your password contains characters that aren't allowed.\n")
menu()
if password_capitals==True:
user_password_score+=5
if password_lowers==True:
user_password_score+=5
if password_numbers==True:
user_password_score+=5
if password_symbols==True:
user_password_score+=5
if password_capitals==True and password_lowers==True and password_numbers==True and password_symbols==True:
user_password_score+=10
if password_numbers==False and password_symbols==False:
user_password_score-=5
if password_capitals==False and password_lowers==False and password_symbols==False:
user_password_score-=5
if password_capitals==False and password_lowers==False and password_numbers==False:
user_password_score-=5
#print(user_password_score)
if user_password_score>20:
print("Your password is strong.\n")
else:
print("That password is weak.\n")
#don't forget you still need to add the thing that checks for 'qwe' and other stuff.
menu()
def check():
用户\密码\分数=0
密码=假
密码=错误
密码\u编号=错误
密码\u符号=False
密码\u解释\u检查=错误
ascii_码=[]
密码\u解释=[]
打印(“密码中唯一允许的字符是大写和小写字母、数字和这些符号;!、$、%、^、&、*、(、)、-、=和+。\n”)
user_password=str(输入(“输入您想要检查的密码:”))
打印(“”)
如果len(用户密码)>24或len(用户密码)64和ascii码[i]96以及ascii码[i]47和ascii码[i]20:
打印(“您的密码很强。\n”)
其他:
打印(“该密码很弱。\n”)
#别忘了,你仍然需要添加检查“qwe”和其他东西的东西。
菜单()
您可以将禁止的序列存储在一组字符串中,并在每次有人使用该序列时降低分数
password = "qwert123"
score = 42 # initial score
sequences = { # all in lowercase because of the `lower()` in the loop
"qwertyuiopasdfghjklzxcvbnm",
"azertyuiopqsdfghjklmwxcvbn",
"abcdefghijklmnopqrstuvwxyz",
"01234567890"
}
match_length = 3 # length threshold for the sanction
sequences.update({s[::-1] for s in sequences}) # do we allow reverse ?
for c in range(len(password)-match_length+1):
for seq in sequences:
if password[c:c+match_length].lower() in seq:
score-=5
print(f"'{password[c:c+match_length]}' => -5 !")
break # Don't flag the same letters more than once
print(score) # 22 (42-4*5)
最简单的方法是在所有可能的序列中使用暴力 创建4个字符串:
“1234567890”
,“qwertyuiop”
,“asdfghjkl”
,“zxcvbnm”
,并使用用户密码中的3个字符循环每个字符串
您可以在检查
功能开始时初始化此列表:
sequences = ["1234567890", "qwertyuiop", "asdfghjkl", "zxcvbnm"]
然后在范围内输入i(len(ascii_代码))
循环添加:
if(i<len(ascii_codes)-2): # since we will be checking for characters up to i+2 in our loop
flag = False # initialize a flag to signal finding a match
for s in sequences: # loop through each of the 4 keyboard sequences
if(s.find(user_password[i: i+3].lower()) != -1):
user_password_score -= 5
flag = True
break
if(flag): break
如果(i我将创建一个相邻密钥序列的列表,如上所述。然后我将创建一个列表来生成长度为3的所有序列,并将每个序列与密码匹配:
from itertools import islice
keyboard_rows = ['1234567890', 'qwertyuiop', 'asdfghjkl', 'zxcvbnm']
def window(seq, n=3):
it = iter(seq)
result = tuple(islice(it, n))
if len(result) == n:
yield result
for elem in it:
result = result[1:] + (elem,)
yield result
for row in keyboard_rows:
for seq in window(row, n=3):
if "".join(seq) in password:
user_password_score -= 15
# scan other direction <--
for seq in window(row[::-1], n=3):
if "".join(seq) in password:
user_password_score -= 15
从itertools导入islice
键盘行=['1234567890','qwertyuiop','asdfghjkl','zxcvbnm']
def窗口(序号,n=3):
it=国际热核实验堆(序号)
结果=元组(islice(it,n))
如果len(结果)==n:
产量结果
对于其中的元素:
结果=结果[1:][+(元素,)
产量结果
对于键盘行中的行:
对于窗口中的序号(行,n=3):
如果“”在密码中加入(seq):
用户密码得分-=15
#扫描其他方向如果允许,您可以在一行中执行此操作:
import re
user_password_score = 42
pwd = 'qwer123'
user_password_score += (lambda z : -5 * len([match.group(1) for match in re.compile('(?=({0}))'.format('|'.join(["({0})".format(w) for w in [x for y in [[s[i:i+3] for i in range(0,len(s)-2)] for s in ["qwertyuiopasdfghjklzxcvbnm", "azertyuiopqsdfghjklmwxcvbn", "abcdefghijklmnopqrstuvwxyz", "01234567890"]] for x in y]]))).finditer(z) ]))(pwd)
此代码等效于:
import re
user_password_score = 42
pwd = 'qwer123'
seqs = ["qwertyuiopasdfghjklzxcvbnm", "azertyuiopqsdfghjklmwxcvbn", "abcdefghijklmnopqrstuvwxyz", "01234567890"]
pattern = re.compile('(?=({0}))'.format('|'.join(["({0})".format(w) for w in [x for y in [[s[i:i+3] for i in range(0,len(s)-2)] for s in seqs] for x in y]])))
penalty = -5 * len([match.group(1) for match in pattern.finditer(pwd) ])
user_password_score += penalty
下面的代码也是等效的(希望也是人类可读的)。我们将一步一步地打印它,以更好地了解它在做什么
import re
def build_pattern(sequences):
all_triplets = []
triplets = []
for seq in sequences:
for i in range(0, len(seq) - 2):
triplets.append(seq[i:i+3])
all_triplets.append(triplets)
triplets = []
expanded_triplets = [ x for y in all_triplets for x in y ]
print("Plain list of triplets: " + str(expanded_triplets))
string_pattern = '|'.join( [ "({0})".format(x) for x in expanded_triplets ] )
lookahead_pattern = '(?=({0}))'.format(string_pattern)
print("Regex expression: " + lookahead_pattern)
return re.compile(lookahead_pattern)
password = 'qwer123'
user_password_score = 42
print("User password score: " + str(user_password_score))
sequences = ["qwertyuiopasdfghjklzxcvbnm",
"azertyuiopqsdfghjklmwxcvbn",
"abcdefghijklmnopqrstuvwxyz",
"01234567890"]
pattern = build_pattern(sequences)
matches = [ match.group(1) for match in pattern.finditer(password) ]
print("Matches : " + str(matches))
matches_count = len(matches)
penalty = -5 * matches_count
print("Penalty: " + str(penalty))
user_password_score += penalty
print("Final score: " + str(user_password_score))
这是输出:
User password score: 42
Plain list of triplets: ['qwe', 'wer', 'ert', 'rty', 'tyu', 'yui', 'uio', 'iop', 'opa', 'pas', 'asd', 'sdf', 'dfg', 'fgh', 'ghj', 'hjk', 'jkl', 'klz', 'lzx', 'zxc', 'xcv', 'cvb', 'vbn', 'bnm', 'aze', 'zer', 'ert', 'rty', 'tyu', 'yui', 'uio', 'iop', 'opq', 'pqs', 'qsd', 'sdf', 'dfg', 'fgh', 'ghj', 'hjk', 'jkl', 'klm', 'lmw', 'mwx', 'wxc', 'xcv', 'cvb', 'vbn', 'abc', 'bcd', 'cde', 'def', 'efg', 'fgh', 'ghi', 'hij', 'ijk', 'jkl', 'klm', 'lmn', 'mno', 'nop', 'opq', 'pqr', 'qrs', 'rst', 'stu', 'tuv', 'uvw', 'vwx', 'wxy', 'xyz', '012', '123', '234', '345', '456', '567', '678', '789', '890']
Regex expression: (?=((qwe)|(wer)|(ert)|(rty)|(tyu)|(yui)|(uio)|(iop)|(opa)|(pas)|(asd)|(sdf)|(dfg)|(fgh)|(ghj)|(hjk)|(jkl)|(klz)|(lzx)|(zxc)|(xcv)|(cvb)|(vbn)|(bnm)|(aze)|(zer)|(ert)|(rty)|(tyu)|(yui)|(uio)|(iop)|(opq)|(pqs)|(qsd)|(sdf)|(dfg)|(fgh)|(ghj)|(hjk)|(jkl)|(klm)|(lmw)|(mwx)|(wxc)|(xcv)|(cvb)|(vbn)|(abc)|(bcd)|(cde)|(def)|(efg)|(fgh)|(ghi)|(hij)|(ijk)|(jkl)|(klm)|(lmn)|(mno)|(nop)|(opq)|(pqr)|(qrs)|(rst)|(stu)|(tuv)|(uvw)|(vwx)|(wxy)|(xyz)|(012)|(123)|(234)|(345)|(456)|(567)|(678)|(789)|(890)))
Matches : ['qwe', 'wer', '123']
Penalty: -15
Final score: 27
在build_pattern
函数中,[x for y in all_triplets for x in y]
是一种将列表列表扩展为普通列表的技巧。类似(lmw)|(mwx)|(wxc)的正则表达式模式在finditer()中使用
告诉我们要查找lmw、mwx和wxc的所有匹配项。当我们将此模式包装到一个前瞻((?=())
)中时我们告诉re
,它还应该包括结果上的重叠匹配。欢迎使用堆栈溢出。请阅读,看看是否可以使用基本部分使您的代码片段更简洁。您也可以发布您的代码。如果x
是布尔值,您可以用if x==True
替换ifx
和如果x==False
与如果不是x
。您还可以编写包含\u数字=any(char.isdigit()表示密码中的字符)
或包含\u大写=any(char.isupper()表示密码中的字符)
。还要注意,循环将在第一次循环后中断occurence@BenoîtPilatte这就是我们所需要的,任何3个字符只会出现一次,并且只会出现在其中一个序列中!@BenoîtPilatte,这是真的,测试代码,你会发现它确实会将分数递减两次。好吧,我被你的break
和你的循环弄糊涂了。