Related
I have a list
passwords = ['baCr',
'/)T.I]DdLNh)^WRIDa_z1',
'izM!Imi',
'NOb5VEhw$[17Q{P',
'i',
'J$52UY$Y',
'T',
'3',
'{77Vt3=2WOCpKWN?',
'$*K',
'H2#u.yUON(i;?',
'zr',
'/}YrhZ7T,X^/}cM0BvR#S)Le$/$Yg#',
'XUGc%',
'+$?D]',
'4?!-G}',
'iMI!G5q]bwI-fE1VT{8rsHWX2tk$29',
'E#',
'lVSh;W9:RyM%Zl9L*;',
'vWYJ%-v?^d:(o',
'.(tp?Hxu{[D+cAhmXGM{ahV3a_fZ!',
'3SXUCASo8/3psxL0p5mw=uf',
'%%7h',
'e(d',
'Ef98S2EUy)mT9MU{#F:zE^8Pb]mg)k',
'k',
'ji[Wtw.#9F$GN%ymi-FU',
'HX?z74lGp]TLqlGp[cRV!w(5]s?7m9',
'5eL',
'Zcrod:Xm',
'}t8bj:RJ4BA6i+x$PlbKL$NNIj',
'H)u(7{lK?Mk!cvUBkzlHXfFyeTL%Sh',
'/]AA-R0A',
'Qq1L$:(s',
'HoDUEPlaKAnDo2;W5}FlY)H(9I',
't0UVz3xgM2Js',
'XJ=#Y=P)z#%7',
'hnDTB7vtCa!MsAIR',
'{R/BvTB?iNS!vKntp$,tvwIC7',
'}2Lz.K',
'P9?+AgbGhp${uMoLqwS(aajG9P.b',
'eldDgR6SZ:v6w^G6ru*vo-',
'-{2{4',
'A=',
'Z{G2p{-#Kz/c}8utFm=WPH_:uTQiT',
'Ql91',
'9R.6J#Y.jWs/}XA0TV4%uRi_k43',
'zcy.Vqfk2xpwgNt-KW?$m',
'X+O+NGT}',
'}]2_',
'Mcuz1;xCE{iHRhsO695ef',
';Q4!nRV7[,LvLDRjke1',
'3BJi9XZW',
'+Rot!',
'nP.kqo1-g2G8ZT$2wxRwI8MAMJ',
'^,$^F7:X=DkDUa?3,L{wf',
'56',
'#O/7CHV4WoMRmq^j$J$/Hk6DUD',
'WkWI5O1J017)5.%!dAaVLhoW',
')$;',
'{5QjA.g:xO#P1',
'M]J%Dxc2]xxc1Kyn7=Ga+sx!#-B9',
':WA',
'2?#',
'HwH_sUUd-i$ln178038#kiQ7T#kZ;',
'13}VI',
'QV+',
'2r-%+=:V',
'DM(DYS),Z==A}',
'fhtmcFtG)CQY0YrB7Aq%0Oogv]g',
'-WFuVnPpZ?z#E{H3I#_:h-v^w9K',
'ceg4g-Y',
'yK8D5*om',
'_ic55w$6N/3/00c',
'^*BhAG4m',
'w#PW',
'D%=^j}l/Qr1l#V*%8d',
'6tJNCnrx,)Fv6*+;q.;PCx1);',
'}Q?}pvhv=beW',
'W$$.C5cI9;Grs653}-5(#p/Nb#8i',
'{(:F6LI',
'r]l#?Fy',
'#N4[qs{!P{Kb[t_sB',
'xoL:UAe(7m$4gjtuakk-ViLNu^b',
'Hc]1:eqc%TzXy8n-?s7VQG.#[nm',
'sM:pqfC',
'8XVO5X7lwt8!B6',
'{$[^',
'7SiL3',
'hV_yN(Kh19%M)5PDV)9oQ5?y*k%2',
'}UhE!SxN7qQVdiNXuw8N+Xxio%I',
'KK:',
'+ZsrD?az!I',
'#_',
'roX:*+2Dl##k-io',
'7Dq',
'TBQ[5',
'9/CX',
'e74j*J^oD',
'1KRmy=FjO[P?kd#+zNQV9:uL(vP',
'di?hp0L*6VZf9:',
'24?%6GW%',
'S#',
'hI7TS!Jo2J2$Zp/_^aIK^(v{K4+',
'W*zIb',
'Qlu#bPU6UtNd',
'n9yX]z0xBQ3C$BG4Jk/,#MG4j[',
'u',
'xL!b.A!zUn',
'I21%',
'ff1Vf=fWqL:sg$gfKnA7;R',
'!6A#W!jwnB-fPP1hGK]sA!B#uitkj',
'qNf.B35u0),}eL)',
'gXB.8I$bQ',
'9v2q0An',
'F?9HZ4',
'z]bgZ8wHsLJQvT!gh(Yn5o[',
'w)K{[3{Z0%u^q',
'SD',
'#c)RM554mY!YD93',
'09YNkm.#VyMPC8cQg5',
'R1}Jw!-rV=Bo{A9#/aWuuP',
'n/CC5xU3hC.itVaF,R=?[^',
'[RiM[xNb',
'=I',
':M[Z%WY,w0.:{c;69ESv_#4S)#n',
'D6-9s.,f=pXiuMF;!l}!N]',
'L?2',
'=#l4,5',
'ZAdAEkQzdmc[O[A,H%9]3}i?',
'0%,OVJ9/}([L[Nq=3mgS:sYHa;',
'Y4:*NU',
'$To.Ce7:hd#YgKFZr+1i.Lx)BIuH',
'nM)#%*H9GiXevMmVm.(Z)]:!BxU!r',
'h?(Y_',
'F(qqHrvx5kL[Xx=4lcs:H!A',
'TgIT+I;GClgST/NB*',
'6=}.',
'+4',
'+BQ5C}:6',
'Dh5VF2Ek#a',
'REB4k%v.c1J*vq?F3#2',
'8}JCK',
'#{?2[X?M[A!_O]RVKqVv%93_#]vx,$',
'H44z_DwaG/A,g)xBCG+9GjAh7e]$!',
'jgct7fezi;jtqc*',
'(_',
'.3:',
'eM4mx)S9HDq_,*rZ;LE0S=U4L2i',
'-]F]']
and I need to find passwords meeting all of the following criteria:
Must not contain any more than 15 characters
Cannot contain any lowercase characters (a-z)
The first and last character cannot be the same
This is my code:
valid=0
for password in passwords:
if len(password)<=15 and password.upper() and password[0]!=password[-1]: valid+=1
I believe the answer is 38, but I keep getting 85? Does anyone see an error in my code that would return the wrong answer? Thanks.
password.upper() returns the password in caps. You need to check they are the same with password.upper() == password:
valid = 0
for password in passwords:
if len(password) <= 15 and password.upper() == password and password[0] != password[-1]:
valid += 1
>>> valid
38
You can see what is happening here:
>>> x = "abc"
# Check the truthiness of x (this is what you were originally doing)
# A non-empty string is always True
>>> bool(x)
True
# x.upper() will just return an uppercase copy
>>> x.upper()
'ABC'
# You need to compare the original with the upper
>>> bool(x == x.upper())
False
You could use a regex to check if no lowercase characters (a-z) are present:
import re
passwords = [
'baCr',
'/)T.I]DdLNh)^WRIDa_z1',
'izM!Imi',
'NOb5VEhw$[17Q{P',
'i',
...
]
valid = 0
for password in passwords:
if len(password) <= 15 and not re.search('[a-z]', password) and password[0] != password[-1]:
valid += 1
print(f'{valid = }')
Output:
valid = 38
Another version:
import re
valid, pat = 0, re.compile(r"([^a-z])[^a-z]{,13}[^\1a-z]$")
for p in passwords:
valid += bool(pat.match(p))
print(valid)
Prints:
38
This is my first ever computer science course so forgive me if this answer is really obvious. I wrote the below code and it worked just fine. I just needed to add an else statement to account for an invalid name input.
Here is is before:
mynames = ['Naomi', 'James', 'Amos', 'Alex', 'Bobbie', 'Josephus', 'Fred', 'Camina', 'Julie', 'Prax', 'Christien', 'Anderson', 'Havelock', 'Ashford', 'Bull', 'Anna', 'Arjun', 'Souther', 'Carissa', 'Samara']
myscores = [89, 98, 76, 76, 84, 93, 82, 64, 63, 75, 76, 86, 96, 75, 86, 100, 99, 87, 84, 94]
name = input("Please enter a name:")
#search through mynames to find the name
while name!='q':
for x in range(20):
if mynames[x] == name:
print(mynames[x], "scored", myscores[x])
name = input("Please enter a name:")
And here it is after:
mynames = ['Naomi', 'James', 'Amos', 'Alex', 'Bobbie', 'Josephus', 'Fred', 'Camina', 'Julie', 'Prax', 'Christien', 'Anderson', 'Havelock', 'Ashford', 'Bull', 'Anna', 'Arjun', 'Souther', 'Carissa', 'Samara']
myscores = [89, 98, 76, 76, 84, 93, 82, 64, 63, 75, 76, 86, 96, 75, 86, 100, 99, 87, 84, 94]
name = input("Please enter a name:")
#search through mynames to find the name
while name!='q':
for x in range(20):
if mynames[x] == name:
print(mynames[x], "scored", myscores[x])
else:
print("That name is not in this class.")
name = input("Please enter a name:")
name = input("Please enter a name:")
It just keeps printing "That name is not in this class." no matter what I type in. SOS
The if statement is evaluated each time through the loop, so you need to keep track of whether the name has been found, and then only print at the end.
For example:
while name!='q':
found = False
for x in range(20):
if mynames[x] == name:
print(mynames[x], "scored", myscores[x])
found = True
break
if not found:
print("That name is not in this class.")
name = input("Please enter a name:")
I think you will really benefit here from using a dictionary. See the following example.
mynames = ['Naomi', 'James', 'Amos', 'Alex', 'Bobbie', 'Josephus', 'Fred', 'Camina', 'Julie', 'Prax', 'Christien', 'Anderson', 'Havelock', 'Ashford', 'Bull', 'Anna', 'Arjun', 'Souther', 'Carissa', 'Samara']
myscores = [89, 98, 76, 76, 84, 93, 82, 64, 63, 75, 76, 86, 96, 75, 86, 100, 99, 87, 84, 94]
name_score_map = dict(zip(mynames, myscores))
name = input("Please enter a name:")
#search through mynames to find the name
while name!='q':
if name in name_score_map:
print(name, "scored", name_score_map[name])
else:
print("That name is not in this class.")
name = input("Please enter a name:")
In the first line, we construct a dictionary that maps the name of a student to the score they got. This takes away the need to iterate through the mynames list to see if a name is in it and then using the corresponding index to grab the score. This, in effect, removes the issue you were facing with print("That name is not in this class.") executing for every iteration in which mynames[x] != name.
We can then check if the name has a score by seeing if the name is in name_score_map. This reduces the time complexity of the search from O(n) to O(1). We can then grab score simply by using the name as a key to the name_score_map dictionary.
I am trying to decode a Huffman encoded string, with the following script:
def decode(input_string, lookup_table):
codes = lookup_table.keys()
result = bytearray()
i = 0
while len(input_string[i:]) != 0:
for code in codes:
if input_string[i:].startswith(code):
result.append(lookup_table[code])
i += len(code)
break
return ''.join((chr(x) for x in result))
lookup_table = {'10': 108, '00': 111, '0111': 114, '010': 119, '0110': 72, '1111': 33, '1110': 32, '1100': 100, '1101': 101}
input_string = '0110110110100011100100001111011001111'
print decode(input_string, lookup_table)
This script gives as output:
'Hello world!'
The script works for this small string, but decoding an encoded version of Hamlet takes 110 seconds. Is there a more efficient and faster way to do this?
This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Closed 5 years ago.
While writing a project for fun, I came across an unfamiliar issue with If and Elif statements. For some reason when the user inputs a dog "type", python ignores the if statements and continues on using the rest of the statement. The program was written in Python 3.6. I have no clue as to why the if and elif statements aren't working properly. Is there a formatting/syntax issue that I am not aware of? Thanks in advance!
def small():
small_list = [0, 15, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80]
small_input = input("How old is your dog?")
print(small_input)
small_age = int(small_input)
small_set2 = small_list[small_age]
print("Your dog's age is: " + str(small_set2))
def medium():
medium_list = [0, 15, 24, 28, 32, 36, 42, 47, 51, 56, 60, 65, 69, 74, 78, 83, 87]
medium_input = input("How old is your dog?")
print(medium_input)
medium_age = int(medium_input)
medium_set2 = medium_list[medium_age]
medium_set2 = str(medium_set2)
print("Your dog's age is: " + str(medium_set2))
def large():
large_input = input("How old is your dog?")
print(large_input)
large_set = [0, 15, 24, 28, 32, 36, 45, 50, 55, 61, 66, 72, 77, 82, 88, 93, 120]
large_age = int(large_input)
large_set2 = large_set[large_age]
large_set2 = str(large_set2)
print("Your dog's age is: " + str(large_set2))
def dog():
dog1 = input('What size dog do you have?')
print(dog1)
if dog1 == 'Small' or 'small':
print("Okay, you have a small dog.")
small()
elif dog1 == 'Medium' or 'medium':
print("Okay, you have a medium dog.")
medium()
elif dog1 == 'Large' or 'large':
print("Okay, you have a large dog.")
large()
else:
print("Sorry, I did not understand that.")
dog()
dog()
if dog1 == 'Small' or 'small':
This statement parses as:
if (dog1 == 'Small') or ('small'):
Because non-empty strings are always truthy, this is equivalent to:
if (dog1 == 'Small') or True:
So the condition is always met.
You probably want this instead:
if dog1 in ('Small', 'small'):
Or even better (ignore all the capitalisation issues):
if dog1.lower() == 'small':
Running mkpasswd -m sha-512 -S salt1234 password results in the following:
$6$salt1234$Zr07alHmuONZlfKILiGKKULQZaBG6Qmf5smHCNH35KnciTapZ7dItwaCv5SKZ1xH9ydG59SCgkdtsTqVWGhk81
I have this snippet of Python code that I thought would output the same, but isn't:
import hashlib, base64
print(base64.b64encode(hashlib.sha512('password' + 'salt1234').digest()))
It instead results in:
nOkBUt6l7zlKAfjtk1EfB0TmckXfDiA4FPLcpywOLORZ1PWQK4+PZVEiT4+9rFjqR3xnaruZBiRjDGcDpxxTig==
Not sure what I am doing wrong.
Another question I have is, how do I tell sha512 function to do custom rounds. It seems to take only 1 argument.
mkpasswd is a front-end to the crypt() function. I don't think it is a straight-forward SHA512 hash here.
A little research points to the specification for SHA256-crypt and SHA512-crypt, which shows the hash is applied a default 5000 times. You can specify a different number of rounds using the -R switch to mkpasswd; -R 5000 indeed gives you the same output:
$ mkpasswd -m sha-512 -S salt1234 -R 5000 password
$6$rounds=5000$salt1234$Zr07alHmuONZlfKILiGKKULQZaBG6Qmf5smHCNH35KnciTapZ7dItwaCv5SKZ1xH9ydG59SCgkdtsTqVWGhk81
The minimum number of rounds offered by the command-line tool is 1000:
$ mkpasswd -m sha-512 -S salt1234 -R 999 password
$6$rounds=1000$salt1234$SVDFHbJXYrzjGi2fA1k3ws01/D9q0ZTAh1KfRF5.ehgjVBqfHUaKqfynXefJ4DxIWxkMAITYq9mmcBl938YQ//
$ mkpasswd -m sha-512 -S salt1234 -R 1 password
$6$rounds=1000$salt1234$SVDFHbJXYrzjGi2fA1k3ws01/D9q0ZTAh1KfRF5.ehgjVBqfHUaKqfynXefJ4DxIWxkMAITYq9mmcBl938YQ//
The algorithm is a bit more involved, requiring you to create several digests. You could instead access the C crypt() function through the crypt.crypt() function, and drive it the same way the mkpasswd commandline does.
It depends on your platform if the SHA512-crypt method is available; the Python 3 version of the crypt module offers a crypt.methods list that tells you what methods your platform supports. Since this use the exact same library mkpasswd uses, your OS obviously does support SHA512-crypt and Python will have access too.
You need to prefix the salt with '$6$ to specify the different method. You can specify the number of rounds by adding a 'rounds=<N>$' string between the '$6$' string and your salt:
import crypt
import os
import string
try: # 3.6 or above
from secrets import choice as randchoice
except ImportError:
from random import SystemRandom
randchoice = SystemRandom().choice
def sha512_crypt(password, salt=None, rounds=None):
if salt is None:
salt = ''.join([randchoice(string.ascii_letters + string.digits)
for _ in range(8)])
prefix = '$6$'
if rounds is not None:
rounds = max(1000, min(999999999, rounds or 5000))
prefix += 'rounds={0}$'.format(rounds)
return crypt.crypt(password, prefix + salt)
This then produces the same output as the mkpasswd command line:
>>> sha512_crypt('password', 'salt1234')
'$6$salt1234$Zr07alHmuONZlfKILiGKKULQZaBG6Qmf5smHCNH35KnciTapZ7dItwaCv5SKZ1xH9ydG59SCgkdtsTqVWGhk81'
>>> sha512_crypt('password', 'salt1234', rounds=1000)
'$6$rounds=1000$salt1234$SVDFHbJXYrzjGi2fA1k3ws01/D9q0ZTAh1KfRF5.ehgjVBqfHUaKqfynXefJ4DxIWxkMAITYq9mmcBl938YQ//'
You need to use crypt.crypt:
>>> import crypt
>>> crypt.crypt('password', '$6$' + 'salt1234')
'$6$salt1234$Zr07alHmuONZlfKILiGKKULQZaBG6Qmf5smHCNH35KnciTapZ7dItwaCv5SKZ1xH9ydG59SCgkdtsTqVWGhk81'
Here is a pure python3 implementation of the sha512_crypt function based on the specification. This is for illustration only, always use crypt.crypt instead!
import hashlib, base64
SHUFFLE_SHA512_INDICES = [
42, 21, 0, 1, 43, 22, 23, 2, 44, 45, 24, 3, 4, 46, 25,
26, 5, 47, 48, 27, 6, 7, 49, 28, 29, 8, 50, 51, 30, 9,
10, 52, 31, 32, 11, 53, 54, 33, 12, 13, 55, 34, 35, 14, 56,
57, 36, 15, 16, 58, 37, 38, 17, 59, 60, 39, 18, 19, 61, 40,
41, 20, 62, 63
]
def shuffle_sha512(data):
return bytes(data[i] for i in SHUFFLE_SHA512_INDICES)
def extend_by_repeat(data, length):
return (data * (length // len(data) + 1))[:length]
CUSTOM_ALPHABET = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
''' Base64 encode based on SECTION 22.e)
'''
def custom_b64encode(data, alphabet = CUSTOM_ALPHABET):
buffer,count,result = 0,0,[]
for byte in data:
buffer |= byte << count
count += 8
while count >= 6:
result.append(buffer & 0x3f)
buffer >>= 6
count -= 6
if count > 0:
result.append(buffer)
return ''.join(alphabet[idx] for idx in result)
''' From http://www.akkadia.org/drepper/SHA-crypt.txt
'''
def sha512_crypt(password, salt, rounds_in = None):
rounds,rounds_defined = 5000, False
if rounds_in is not None:
rounds,rounds_defined = rounds_in, True
assert 1000 <= rounds <= 999999999
hash = hashlib.sha512
salt_prefix = '$6$'
password = password.encode('utf8')
salt = salt.encode('ascii')[:16]
A = hash() # SECTION 1.
A.update(password) # SECTION 2.
A.update(salt) # SECTION 3.
B = hash() # SECTION 4.
B.update(password) # SECTION 5.
B.update(salt) # SECTION 6.
B.update(password) # SECTION 7.
digestB = B.digest(); # SECTION 8.
A.update(extend_by_repeat(digestB, len(password))) # SECTION 9., 10.
# SECTION 11.
i = len(password)
while i > 0:
if i & 1:
A.update(digestB) # SECTION 11.a)
else:
A.update(password) # SECTION 11.b)
i = i >> 1
digestA = A.digest() # SECTION 12.
DP = hash() # SECTION 13.
# SECTION 14.
for _ in range(len(password)):
DP.update(password)
digestDP = DP.digest() # SECTION 15.
P = extend_by_repeat(digestDP, len(password)) # SECTION 16.a), 16.b)
DS = hash() # SECTION 17.
# SECTION 18.
for _ in range(16 + digestA[0]):
DS.update(salt)
digestDS = DS.digest() # SECTION 19.
S = extend_by_repeat(digestDS, len(salt)) # SECTION 20.a), 20.b)
# SECTION 21.
digest_iteration_AC = digestA
for i in range(rounds):
C = hash() # SECTION 21.a)
if i % 2:
C.update(P) # SECTION 21.b)
else:
C.update(digest_iteration_AC) # SECTION 21.c)
if i % 3:
C.update(S) # SECTION 21.d)
if i % 7:
C.update(P) # SECTION 21.e)
if i % 2:
C.update(digest_iteration_AC) # SECTION 21.f)
else:
C.update(P) # SECTION 21.g)
digest_iteration_AC = C.digest() # SECTION 21.h)
shuffled_digest = shuffle_sha512(digest_iteration_AC)
prefix = salt_prefix # SECTION 22.a)
# SECTION 22.b)
if rounds_defined:
prefix += 'rounds={0}$'.format(rounds_in)
return (prefix
+ salt.decode('ascii') # SECTION 22.c)
+ '$' # SECTION 22.d)
+ custom_b64encode(shuffled_digest) # SECTION 22.e)
)
actual = sha512_crypt('password', 'salt1234')
expected = '$6$salt1234$Zr07alHmuONZlfKILiGKKULQZaBG6Qmf5smHCNH35KnciTapZ7dItwaCv5SKZ1xH9ydG59SCgkdtsTqVWGhk81'
print(actual)
print(expected)
assert actual == expected