Pass cracker how not use four loops for four letters combination - python-3.x

I was practising for educational purpose with simply password cracker.
I know that I could use itertool but in my case when I'm learning I
would miss facing problems and learning on them and indeed I've met one
which is not giving me a peace.
What I want to learn is if I need get for example four combinations, so
how to get in a loop first letter 'a',then another step'a' and again 'a'
and 'a', to have 'aaaa' later on'abaa' etc.
So I wrote that:
import string
passe = 'zulu'
mylist = []
#letters = string.ascii_lowercase
letters = ['a','b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'w', 'q', 'y', 'z']
mineset= set()
for a in letters:
for b in letters:
for c in letters:
for d in letters:
s = a + b + c + d
mylist.append(s)
mineset=set(mylist)
k = sorted(mineset)
print(k)
for i in k:
if i == passe:
print('got it: ', i )
print(passe in k)
It works in someway but the problems are:
I had to made a set from list because combinations
were repeated.
And finally, I was struggling with making it in without creating four
loops for four letters, something like that:
To try to solve those I went with that approach:
letters = ['a','b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'w', 'q', 'y', 'z']
password = 'pass'
combin = ''
lista=[]
for x in range(1,5):
for y in letters:
combin +=y
lista.append(combin)
combin=''
mineset=set(lista)
print(mineset)
for i in lista:
if i == password:
print('pass:', i)
But the results are disspainting:
{'abc', 'a', 'ab', 'abcd', 'abcde'}
I was seating on it for a long day but can't even closely achieve
similar effect to 4 loops in previous code.

While I don't recommend this approach as a general rule, for purposes of learning here is a way to achieve what you want:
def getCombos(lts):
rslt = []
for l1 in lts:
for l2 in lts:
for l3 in lts:
for l4 in lts:
s = l1+l2+l3+l4
rslt.append(s)
return rslt
letters = 'abcdefghijklmnopqrstuvwxyz'
getCombos(letters)
As is illustrated by a simple example, this code is of O(n^x) in complexity where n = number of characters and x = length of the letters. This approach, quickly becomes unwieldly as the following example illustrates:
getCombos('abc")
yields 81 entries including:
['aaaa',
'aaab',
'aaac',
'aaba',
'aabb',
'aabc',
'aaca',
'aacb',
'aacc',
'abaa',
'abab',
'abac',
'abba',
'abbb',
'abbc',
'abca',
'abcb',
'abcc',
'acaa',
'acab',
'acac',
'acba',
'acbb',
'acbc',
'acca',
'accb',
'accc',
'baaa',
'baab',
'baac',
'baba',
'babb',
'babc',
'baca',
'bacb',
'bacc',
'bbaa',
'bbab',
'bbac',
'bbba',
'bbbb',
'bbbc',
'bbca',
'bbcb',
'bbcc',
'bcaa',
'bcab',
'bcac',
'bcba',
'bcbb',
'bcbc',
'bcca',
'bccb',
'bccc',
'caaa',
'caab',
'caac',
'caba',
'cabb',
'cabc',
'caca',
'cacb',
'cacc',
'cbaa',
'cbab',
'cbac',
'cbba',
'cbbb',
'cbbc',
'cbca',
'cbcb',
'cbcc',
'ccaa',
'ccab',
'ccac',
'ccba',
'ccbb',
'ccbc',
'ccca',
'cccb',
'cccc']

Related

Why wont my while loop work when adding my def function

This is my code below and I cant seem to make my while loop run continuosly.
#alphabet list
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
# user input message
text = input("Type your message:\n")
# user input shift amount
shift = int(input("Type the shift number:\n"))
# def function
def encode(plain_text, shift_amount):
cipher_text = ''
for letter in plain_text:
position = alphabet.index(letter)
new_position = position + shift_amount
new_letter = alphabet[new_position]
cipher_text += new_letter
print(f'The encoded string is: {cipher_text}')
encode(plain_text = text, shift_amount = shift)
while True:
if text != 'q':
continue
I am not sure if I set this up correctly.
Executed like this, your prompt will ask for two inputs (your message and the shift number), then execute encode. Then it'll enter the while True loop and loop forever. Why?
Two reasons:
If you didn't input q at the first step, you will never meet the condition
Even though you did set text = "q", your loop will never stop. You need to use the break statement to make an infinite loop stop:
while True:
if text == 'q':
break
I think what you want is:
while True:
text = input("Type your message (or q to quit):\n")
shift = int(input("Type the shift number:\n"))
if text == 'q':
break
encode(text, shift_amount=shift)
Thus, your code will loop and ask & encode an input until to type "q"
You need to put the following lines inside the while loop for it to continuously run (as I think you want):
# user input message
text = input("Type your message:\n")
# user input shift amount
shift = int(input("Type the shift number:\n"))
encode(plain_text = text, shift_amount = shift)
As suggested in other answers, you should call input and encode inside the while loop. However, I think only the first input should be before the if clause like so:
while True:
# user input message
text = input("Type your message:\n")
if text != 'q':
break
# user input shift amount
shift = int(input("Type the shift number:\n"))
encode(plain_text=text, shift_amount=shift)
Also, you don't need to define alphabet as a list of characters, you can simply define it as a string:
alphabet = 'abcdefghifklmnopqrstuvwxyz'
or, even better, just import it from string:
import string
alphabet = string.ascii_lowercase

.append() is replacing element, instead of adding new element to the list

I am trying to create a cipher program, here text entered by the user will be shifted to the letters according to the shift variable. so here I have created an empty list called encrypt and trying to append characters after shifting them to the list.
But it's just replacing the letter in the list instead of adding a new item in the list.
Here's the code:
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
#direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n")
text = input("Type your message:\n").lower()
shift = int(input("Type the shift number:\n"))
#TODO-1: Create a function called 'encrypt' that takes the 'text' and 'shift' as inputs.
def encrypt(text,shift):
for letter in text:
encrypted = []
position = alphabet.index(letter) + shift
encrypted.append(alphabet[position])
print(''.join(encrypted))
encrypt(text,shift)
Thank you
You are basically overwriting your list everytime in the loop. here
def encrypt(text,shift):
for letter in text:
encrypted = [] #This runs every iteration, so there will be only 1 at end
position = alphabet.index(letter) + shift
encrypted.append(alphabet[position])
print(''.join(encrypted))
Move it out of the loop, things must be fine.
def encrypt(text,shift):
encrypted = []
for letter in text:
position = alphabet.index(letter) + shift
encrypted.append(alphabet[position])
print(''.join(encrypted))

Python 3.8 sort - Lambda function behaving differently for lists, strings

Im trying to sort a list of objects based on frequency of occurrence (increasing order) of characters. Im seeing that the sort behaves differently if list has numbers versus characters. Does anyone know why this is happening?
Below is a list of numbers sorted by frequency of occurrence.
# Sort list of numbers based on increasing order of frequency
nums = [1,1,2,2,2,3]
countMap = collections.Counter(nums)
nums.sort(key = lambda x: countMap[x])
print(nums)
# Returns correct output
[3, 1, 1, 2, 2, 2]
But If I sort a list of characters, the order of 'l' and 'o' is incorrect in the below example:
# Sort list of characters based on increasing order of frequency
alp = ['l', 'o', 'v', 'e', 'l', 'e', 'e', 't', 'c', 'o', 'd', 'e']
countMap = collections.Counter(alp)
alp.sort(key = lambda x: countMap[x])
print(alp)
# Returns Below output - characters 'l' and 'o' are not in the correct sorted order
['v', 't', 'c', 'd', 'l', 'o', 'l', 'o', 'e', 'e', 'e', 'e']
# Expected output
['v', 't', 'c', 'd', 'l', 'l', 'o', 'o', 'e', 'e', 'e', 'e']
Sorting uses stable sort - that means if you have the same sorting criteria for two elements they keep their relative order/positioning (here it being the amount of 2 for both of them).
from collections import Counter
# Sort list of characters based on increasing order of frequency
alp = ['l', 'o', 'v', 'e', 'l', 'e', 'e', 't', 'c', 'o', 'd', 'e']
countMap = Counter(alp)
alp.sort(key = lambda x: (countMap[x], x)) # in a tie, the letter will be used to un-tie
print(alp)
['c', 'd', 't', 'v', 'l', 'l', 'o', 'o', 'e', 'e', 'e', 'e']
This fixes it by using the letter as second criteria.
To get your exact output you can use:
# use original position as tie-breaker in case counts are identical
countMap = Counter(alp)
pos = {k:alp.index(k) for k in countMap}
alp.sort(key = lambda x: (countMap[x], pos[x]))
print(alp)
['v', 't', 'c', 'd', 'l', 'l', 'o', 'o', 'e', 'e', 'e', 'e']
See Is python's sorted() function guaranteed to be stable? or https://wiki.python.org/moin/HowTo/Sorting/ for details on sorting.

Appending list works for the first iteration but after I get list index out of range

I'm trying to make a Caesar cipher shift. Whenever I go about shifting the character based on the alphabet position it gives me the "list index out of range" error.
password = input('type in the word you want to turn into a password: ')
shift = int(input('What do you want your caesar shift to be? '))
new_password = []
password = list(password)
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
'v', 'w', 'x', 'y', 'z']
i = 0
for num in range(0, len(password)):
for letter in alphabet:
i += 1
if password[num] == letter:
move = i
new_password.append(alphabet[(move + shift) - 1])
print(new_password[num])
I expected that this program would continue to continue to append letters to new_password based on how long the first password was. However after the first letter, I get the "list index out of range"
What's happening here is that your move and shift values end up being outside of the index values available in alphabet. You will need to add special cases to wrap around the indexes when (move + shift) - 1 is greater than the length of alphabet.

The English alphabet as a vector of characters in Rust

The title says it all. I want to generate the alphabet as a vector of characters. I did consider simply creating a range of 97-122 and converting it to characters, but I was hoping there would be a nicer looking way, such as Python's string.ascii_lower.
The resulting vector or string should have the characters a-z.
Hard-coding this sort of thing makes sense, as it can then be a compiled constant, which is great for efficiency.
static ASCII_LOWER: [char; 26] = [
'a', 'b', 'c', 'd', 'e',
'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y',
'z',
];
(Decide for yourself whether to use static or const.)
This is pretty much how Python does it in string.py:
lowercase = 'abcdefghijklmnopqrstuvwxyz'
# ...
ascii_lowercase = lowercase
Collecting the characters of a str doesn't seem like a bad idea...
let alphabet: Vec<char> = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".chars().collect();
Old question but you can create a range of chars, so
('a'..='z').into_iter().collect::<Vec<char>>()

Resources