I am doing a task in class about a password guesser. I stumbled into a lot of problems trying to solve this task, my first approach was to use for loops (code below), but I realized that the amount of 'for loops' is equal to the length of the string.
a_z = 'abcdefghijklmnopqrstuvwxyz'
pasw = 'dog'
tests = 0
guess = ''
azlen = len(a_z)
for i in range(azlen):
for j in range(azlen):
for k in range(azlen):
guess = a_z[i] + a_z[j] + a_z[k]
tests += 1
if guess == pasw:
print('Got "{}" after {} tests'.format(guess, str(tests)))
break
input()
The program above is very concrete. It only works if there are exactly 3 characters entered. I read that you could use a package called intertools, however, I really want to find another way of doing this. I thought about using recursion but don't even know where to start.
import string
import itertools
for possible_password in itertools.permutations(string.ascii_letters, 3):
print(possible_password)
If you don't want to use itertools you can certainly do this with recursion, which will work with passwords of any (reasonable) length—it's not wired to three characters. Basically, each recursive call will attempt to append a new character from your alphabet to your running value of guess. The base case is when the guess attains the same length as value you're seeking, in which case you check for a match. If a match is found, return an indication that you have succeeded (I used return True) so you can short circuit any further searching. Otherwise, return a failure indication (return False). The use of a global counter makes it a bit uglier, but produces the same results you reported.
ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
def brute_force_guesser(passwd, guess = ''):
global _bfg_counter
if len(guess) == 0:
_bfg_counter = 0
if len(guess) == len(passwd):
_bfg_counter += 1
if guess == passwd:
print('Got "{}" after {} tests'.format(guess, str(_bfg_counter)))
return True
return False
else:
for c in ALPHABET:
if brute_force_guesser(passwd, guess + c):
return True
return False
brute_force_guesser('dog') # => Got "dog" after 2399 tests
brute_force_guesser('doggy') # => Got "doggy" after 1621229 tests
One way to avoid the global counter is by using multiple return values:
ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
def brute_force_guesser(target, guess = '', counter = 0):
if len(guess) == len(target):
counter += 1
if guess == target:
print('Got "{}" after {} tests'.format(guess, str(counter)))
return True, counter
return False, counter
else:
for c in ALPHABET:
target_found, counter = brute_force_guesser(target, guess + c, counter)
if target_found:
return True, counter
return False, counter
brute_force_guesser('dog') # => Got "dog" after 2399 tests
brute_force_guesser('doggy') # => Got "doggy" after 1621229 tests
Here is my full answer, sorry if it's not neat, I'm still new to coding in general. The credit goes to #JohnColeman for the great idea of using bases.
import math
global guess
pasw = str(input('Input password: '))
chars = 'abcdefghijklmnopqrstuvwxyz' #only limeted myself to lowercase for simplllicity.
base = len(chars)+1
def cracker(pasw):
guess = ''
tests = 1
c = 0
m = 0
while True:
y = tests
while True:
c = y % base
m = math.floor((y - c) / base)
y = m
guess = chars[(c - 1)] + guess
print(guess)
if m == 0:
break
if guess == pasw:
print('Got "{}" after {} tests'.format(guess, str(tests)))
break
else:
tests += 1
guess = ''
cracker(pasw)
input()
import itertools
import string
def guess_password(real):
chars = string.ascii_lowercase + string.digits
attempts = 0
for password_length in range(1, 20):
for guess in itertools.product(chars, repeat=password_length):
attempts += 1
guess = ''.join(guess)
if guess == real:
return 'the password is {}, found in {} guesses.'.format(guess, attempts)
print(guess, attempts)
print(guess_password('abc'))
Related
I am trying to make a random word/phrase generator that is like the one that bitwarden has (in python3). But the issue I am running into and need some help with is the addition of 1 number at the end of 1 of the words that is shown.
Something like this Referee-Outrank-Cymbal-Cupping-Cresting-Fiber7-Expensive-Myth-Unveiling-Grasp-Badland-Epiphany-Simplify-Munchkin-Pastrami-Spiffy-Gladly-Skeptic-Retouch-Buckskin
What is very important here is that the number is "random" and the word it is attached to is "random".
Code I have written so far:
Word list I am using is https://svnweb.freebsd.org/csrg/share/dict/words?view=co&content-type=text/plain but without ' in any of the words.
#pycryptodome==3.15.0
from Crypto.Random import random
import beaupy
import os
def clear():
os.system('clear||cls')
def main():
while True:
try:
number = int(beaupy.prompt("How many words?: "))
except ValueError as e:
print(f'Oops! Something went wrong.\nError: {e}\n\n')
input('Press "enter" to continue...')
clear()
continue
if number > 20 or number < 3:
print("20 words is the maximum number of words you can use. And 5 words is the minimum.\n\n")
input('Press "enter" to continue...')
clear()
else:
break
cwd = os.getcwd()
word_path = f"{cwd}/words.txt"
with open(word_path, 'r') as fh:
words = fh.read().lower()
word_list = words.splitlines() #list of words
sep = beaupy.prompt('Line separator? (leave empty for default "-"): ')
if sep == '' or sep == ',':
sep = '-'
#Returns True or False. Basically Yes or No?
if beaupy.confirm("Capitalize?"):
"""Make list of words with the first letter capitalized."""
c_lst = []
for i in word_list:
c_lst.append(i.title())
capital_words = f'{sep}'.join(random.choice(c_lst) for _ in range(number))
else:
default_words = f'{sep}'.join(random.choice(word_list) for _ in range(number))
if beaupy.confirm("Number?"):
rn_num = random.randint(0, 9) # <-- Get a random number to be used with only 1 of the words defined in capital_words or default_words below.
#I don't know what to do here... but I need to have a version with the number and one without. (default)
if __name__ == '__main__':
clear()
main()
I am not exactly familiar with string manipulation and searching for answers online just isn't giving me any help with the very specific thing I'm trying to do. All I want is for 1 word in the resulting string to have a "random" number attached to it.
I don't know if I need to re order my code and have it be done a different way. I am having such a headache with this. Any help would be great.
Edit#1
Additional and unrelated note, If anyone knows of a better word list to use, please let me know!
If I am understanding correctly, here is a solution:
#Returns True or False. Basically Yes or No?
capital_words = ''
default_words = ''
if beaupy.confirm("Capitalize?"):
"""Make list of words with the first letter capitalized."""
c_lst = []
for i in word_list:
c_lst.append(i.title())
capital_words = f'{sep}'.join(random.choice(c_lst) for _ in range(number))
else:
default_words = f'{sep}'.join(random.choice(word_list) for _ in range(number))
if beaupy.confirm("Number?"):
rn_num = random.randint(0, 9) # <-- Get a random number to be used with only 1 of the words defined in capital_words or default_words below.
#I don't know what to do here... but I need to have a version with the number and one without. (default)
word_index = random.randint(0, number - 1) # Get random index that is in the word list
if default_words != '':
word_with_number = default_words.split(sep)
else:
word_with_number = capital_words.split(sep)
word_with_number[word_index] = word_with_number[word_index] + str(rn_num)
word_with_number = sep.join(word_with_number)
print(word_with_number)
if default_words != '':
print(default_words)
else:
print(capital_words)
OUTPUT:
detroit-elide-windbag-purge-tort-mortician-codex7-annex-fairy-suntanning
detroit-elide-windbag-purge-tort-mortician-codex-annex-fairy-suntanning
With some help from AnonymousFrog. I was able to get my code working.
The following is the now working code.
from Crypto.Random import random
import beaupy
import os
def clear():
os.system('clear||cls')
def main():
while True:
try:
number = int(beaupy.prompt("How many words?: "))
except ValueError as e:
print(f'Oops! Something went wrong.\nError: {e}\n\n')
input('Press "enter" to continue...')
clear()
continue
if number > 20 or number < 3:
print("20 words is the maximum number of words you can use. And 5 words is the minimum.\n\n")
input('Press "enter" to continue...')
clear()
else:
break
cwd = os.getcwd()
word_path = f"{cwd}/words.txt"
with open(word_path, 'r') as fh:
words = fh.read().lower()
word_list = words.splitlines() #list of words
sep = beaupy.prompt('Line separator? (leave empty for default "-"): ')
if sep == '' or sep == ',':
sep = '-'
#Returns True or False. Basically Yes or No?
capital_words = ''
default_words = ''
if beaupy.confirm("Capitalize?"):
"""Make list of words with the first letter capitalized."""
c_lst = []
for i in word_list:
if len(i) < 3 or len(i) > 9:
pass
else:
c_lst.append(i.title())
cap = True
capital_words = f'{sep}'.join(random.choice(c_lst) for _ in range(number))
else:
cap = False
default_words = f'{sep}'.join(random.choice(word_list) for _ in range(number))
if beaupy.confirm("Number?"):
num = True
rn_num = random.randint(0, 9) # <-- Get a random number to be used with only 1 of the words defined in capital_words or default_words below.
word_index = random.randint(0, number - 1) # Get random index that is in the word list
if default_words != '':
word_with_number = default_words.split(sep)
else:
word_with_number = capital_words.split(sep)
word_with_number[word_index] = word_with_number[word_index] + str(rn_num)
word_with_number = sep.join(word_with_number)
else:
num = False
if cap == True and num == False:
print(capital_words)
if cap == False and num == False:
print(default_words)
if num == True:
print(word_with_number)
Thanks for the help!
(if anyone knows of a better word list to use, feel free to let me know)
import random
import string
lowercase = [string.ascii_lowercase]
uppercase = [string.ascii_uppercase]
number = [string.digits]
symbols = [string.punctuation]
password_outputs = string.ascii_lowercase + string.ascii_uppercase + string.digits +string.punctuation
I was wondering if there was a better way to create a more secure password then just using the ascii strings with random
Done following changes in your code.
import random
import string
lowercase = [string.ascii_lowercase]
uppercase = [string.ascii_uppercase]
number = [string.digits]
symbols = [string.punctuation]
password_outputs = string.ascii_lowercase + string.ascii_uppercase + string.digits +string.punctuation
print("Welcome to the RPG!")
gen_password=''
stop = False
num_char = 0. # include this line if you want that earlier user entered 3 and in next iteration 5 so total you want 8 character password if you only want 5 character password then you can remove this line
while not stop:
gen_password='' # each time it will default to empty
num_char += int(input('Enter in the ammount of characters for the desired password: '))
while num_char > 0:
rand_char = random.choice(password_outputs)
gen_password += rand_char
num_char -= 1
#basically a redstone repeater that decreases in value until it hits 0 and can contiue. User able to pick start value
if num_char == 0:
print(gen_password)
#ensures that only the final product of while loop is printed
#if num_char != int:
#stop = False
#want to make it more secure against non-integer inputs, not sure how to go about this
user_continue = input('Would you like to generate a longer password? (y/n): ')
if user_continue == 'y':
stop = False
elif user_continue == 'n':
stop = True
else:
print('Invalid Operation, running generator again')
stop = False
print("Have a nice day!")
I have a sequence print(lcp(["flower","flow","flight", "dog"])) which should return fl. Currently I can get it to return flowfl.
I can locate the instances where o or w should be removed, and tried different approaches to remove them. However they seem to hit syntax issue, which I cannot seem to resolve by myself.
I would very much appreciate a little guidance to either have the tools to remedy this issue my self, or learn from a working proposed solution.
def lcp(strs):
if not isinstance(strs, list) or len(strs) == 0:
return ""
if len(strs) == 1:
return strs[0]
original = strs[0]
original_max = len(original)
result = ""
for _, word in enumerate(strs[1:],1):
current_max = len(word)
i = 0
while i < current_max and i < original_max:
copy = "".join(result)
if len(copy) and copy[i-1] not in word:
# result = result.replace(copy[i-1], "")
# result = copy[:i-1]
print(copy[i-1], copy, result.index(copy[i-1]), i, word)
if word[i] == original[i]:
result += word[i]
i += 1
return result
print(lcp(["flower","flow","flight", "dog"])) # returns flowfl should be fl
print(lcp(["dog","car"])) # works
print(lcp(["dog","racecar","car"])) # works
print(lcp([])) # works
print(lcp(["one"])) # works
I worked on an alternative which does not be solve removing inside the same loop, adding a counter at the end. However my instincts suggest it can be solved within the for and while loops without increasing code bloat.
if len(result) > 1:
counter = {char: result.count(char) for char in result}
print(counter)
I have solved this using the below approach.
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
N = len(strs)
if N == 1:
return strs[0]
len_of_small_str, small_str = self.get_min_str(strs)
ans = ""
for i in range(len_of_small_str):
ch = small_str[i]
is_qualified = True
for j in range(N):
if strs[j][i] != ch:
is_qualified = False
break
if is_qualified:
ans += ch
else:
break
return ans
def get_min_str(self, A):
min_len = len(A[0])
s = A[0]
for i in range(1, len(A)):
if len(A[i]) < min_len:
min_len = len(A[i])
s = A[i]
return min_len, s
Returns the longest prefix that the set of words have in common.
def lcp(strs):
if len(strs) == 0:
return ""
result = strs[0]
for word in strs[1:]:
for i, (l1, l2) in enumerate(zip(result, word)):
if l1 != l2:
result = result[:i]
break
else:
result = result[:i+1]
return result
Results:
>>> print(lcp(["flower","flow","flight"]))
fl
>>> print(lcp(["flower","flow","flight", "dog"]))
>>> print(lcp(["dog","car"]))
>>> print(lcp(["dog","racecar","car"]))
>>> print(lcp([]))
>>> print(lcp(["one"]))
one
>>> print(lcp(["one", "one"]))
one
You might need to rephrase your goal.
By your description you don't want the longest common prefix, but the prefix that the most words have in common with the first one.
One of your issues is that your tests only test one real case and four edgecases. Make some more real examples.
Here's my proposition: I mostly added the elif to check if we already have a difference on the first letter to then discard the entry.
It also overwrites the original to rebuild the string based on the common prefix with the next word (if there are any)
def lcp(strs):
if not isinstance(strs, list) or len(strs) == 0:
return ""
if len(strs) == 1:
return strs[0]
original = strs[0]
result = ""
for word in strs[1:]:
i = 0
while i < len(word) and i < len(original) :
if word[i] == original[i]:
result += word[i]
elif i == 0:
result = original
break
i += 1
original = result
result = ""
return original
print(lcp(["flower","flow","flight", "dog"])) # fl
print(lcp(["shift", "shill", "hunter", "shame"])) # sh
print(lcp(["dog","car"])) # dog
print(lcp(["dog","racecar","car"])) # dog
print(lcp(["dog","racecar","dodge"])) # do
print(lcp([])) # [nothing]
print(lcp(["one"])) # one
A friend of mine told me that she needs help with some homework, I owe her a favor so I said fine, why not. she needed help with a program that checks a sequence, if the sequence is made of the same 2 chars one after the other it will print "yes" (for example "ABABABAB" or "3$3$3$3:)
The program works fine with even length strings (for example "abab") but not with odd length one ("ububu")
I made the code messy and "bad" in purpose, computers is her worst subject so I don't want it to look obvious that someone else wrote the code
the code -
def main():
StringInput = input('your string here - ')
GoodOrBad = True
L1 = StringInput[0]
L2 = StringInput[1]
i = 0
while i <= len(StringInput):
if i % 2 == 0:
if StringInput[i] == L1:
i = i + 1
else:
GoodOrBad = False
break
if i % 2 != 0:
if StringInput[i] == L2:
i = i + 1
else:
GoodOrBad = False
break
if GoodOrBad == True:
print("yes")
elif GoodOrBad != True:
print("no")
main()
I hope someone will spot the problem, thanks you if you read everything :)
How about (assuming s is your string):
len(set(s[::2]))==1 & len(set(s[1::2]))==1
It checks that there is 1 char in the even locations, and 1 char in the odd locations.
a) Showing your friend bad and messy code makes her hardly a better programmer. I suggest that you explain to her in a way that she can improve her programming skills.
b) If you check for the character at the even position and find that it is good, you increment i. After that, you check if i is odd (which it is, since you found a valid character at the even position), you check if the character is valid. Instead of checking for odd position, an else should do the trick.
You can do this using two methods->
O(n)-
def main():
StringInput = input('your string here - ')
GoodOrBad = True
L1 = StringInput[0]
L2 = StringInput[1]
i = 2
while i < len(StringInput):
l=StringInput[i]
if(l==StringInput[i-2]):
GoodOrBad=True
else:
GoodOrBad=False
i+=1
if GoodOrBad == True:
print("yes")
elif GoodOrBad == False:
print("no")
main()
Another method->
O(1)-
def main():
StringInput = input('your string here - ')
GoodOrBad = True
L1 = set(StringInput[0::2])
L2 = set(StringInput[1::2])
if len(L1)==len(L2):
print("yes")
else:
print("no")
main()
There is a lot in this that I would change, but I am just showing the minimal changes to get it to work. There are 2 issues.
You have an off by one error in the code:
i = 0
while i <= len(StringInput):
# in the loop you index into StringInput
StringInput[i]
Say you have 5 characters in StringInput. Because your while loop is going from i = 0 to i < = len(StringInput), it is going to go through the values [0, 1, 2, 3, 4, 5]. That last index is a problem since it is off the end off StringInput.
It will throw a 'string index out of range' exception.
You need to use:
while i < len(StringInput)
You also need to change the second if to an elif (actually it could just be an else, but...) so you do not try to test both in the same pass of the loop. If you go into the second if after the last char has been tested in the first if it will go out of range again.
elif i % 2 != 0:
So the corrected code would be:
def main():
StringInput = input('your string here - ')
GoodOrBad = True
L1 = StringInput[0]
L2 = StringInput[1]
i = 0
while i < len(StringInput):
if i % 2 == 0:
if StringInput[i] == L1:
i = i + 1
else:
GoodOrBad = False
break
elif i % 2 != 0:
if StringInput[i] == L2:
i = i + 1
else:
GoodOrBad = False
break
if GoodOrBad == True:
print("yes")
elif GoodOrBad != True:
print("no")
main()
def main():
StringInput = input('your string here - ')
MaxLength = len(StringInput) // 2 + (len(StringInput) % 2 > 0)
start = StringInput[:2]
chained = start * MaxLength
GoodOrBad = chained[:len(StringInput)] == StringInput
if GoodOrBad == True:
print("yes")
elif GoodOrBad != True:
print("no")
I believe this does what you want. You can make it messier if this isn't bad enough.
How can I check if input is a letter or character in Python?
Input should be amount of numbers user wants to check.
Then program should check if input given by user belongs to tribonacci sequence (0,1,2 are given in task) and in case user enter something different than integer, program should continue to run.
n = int(input("How many numbers do you want to check:"))
x = 0
def tribonnaci(n):
sequence = (0, 1, 2, 3)
a, b, c, d = sequence
while n > d:
d = a + b + c
a = b
b = c
c = d
return d
while x < n:
num = input("Number to check:")
if num == "":
print("FAIL. Give number:")
elif int(num) <= -1:
print(num+"\tFAIL. Number is minus")
elif int(num) == 0:
print(num+"\tYES")
elif int(num) == 1:
print(num+"\tYES")
elif int(num) == 2:
print(num+"\tYES")
else:
if tribonnaci(int(num)) == int(num):
print(num+"\tYES")
else:
print(num+"\tNO")
x = x + 1
You can use num.isnumeric() function that will return You "True" if input is number and "False" if input is not number.
>>> x = raw_input()
12345
>>> x.isdigit()
True
You can also use try/catch:
try:
val = int(num)
except ValueError:
print("Not an int!")
For your use, using the .isdigit() method is what you want.
For a given string, such as an input, you can call string.isdigit() which will return True if the string is only made up of numbers and False if the string is made up of anything else or is empty.
To validate, you can use an if statement to check if the input is a number or not.
n = input("Enter a number")
if n.isdigit():
# rest of program
else:
# ask for input again
I suggest doing this validation when the user is inputting the numbers to be checked as well. As an empty string "" causes .isdigit() to return False, you won't need a separate validation case for it.
If you would like to know more about string methods, you can check out https://www.quackit.com/python/reference/python_3_string_methods.cfm which provides information on each method and gives examples of each.
This question keeps coming up in one form or another. Here's a broader response.
## Code to check if user input is letter, integer, float or string.
#Prompting user for input.
userInput = input("Please enter a number, character or string: ")
while not userInput:
userInput = input("Input cannot be empty. Please enter a number, character or string: ")
#Creating function to check user's input
inputType = '' #See: https://stackoverflow.com/questions/53584768/python-change-how-do-i-make-local-variable-global
def inputType():
global inputType
def typeCheck():
global inputType
try:
float(userInput) #First check for numeric. If this trips, program will move to except.
if float(userInput).is_integer() == True: #Checking if integer
inputType = 'an integer'
else:
inputType = 'a float' #Note: n.0 is considered an integer, not float
except:
if len(userInput) == 1: #Strictly speaking, this is not really required.
if userInput.isalpha() == True:
inputType = 'a letter'
else:
inputType = 'a special character'
else:
inputLength = len(userInput)
if userInput.isalpha() == True:
inputType = 'a character string of length ' + str(inputLength)
elif userInput.isalnum() == True:
inputType = 'an alphanumeric string of length ' + str(inputLength)
else:
inputType = 'a string of length ' + str(inputLength) + ' with at least one special character'
#Calling function
typeCheck()
print(f"Your input, '{userInput}', is {inputType}.")
If using int, as I am, then I just check if it is > 0; so 0 will fail as well. Here I check if it is > -1 because it is in an if statement and I do not want 0 to fail.
try:
if not int(data[find]) > -1:
raise(ValueError('This is not-a-number'))
except:
return
just a reminder.
You can check the type of the input in a manner like this:
num = eval(input("Number to check:"))
if isinstance(num, int):
if num < 0:
print(num+"\tFAIL. Number is minus")
elif tribonnaci(num) == num: # it would be clean if this function also checks for the initial correct answers.
print(num + '\tYES')
else:
print(num + '\NO')
else:
print('FAIL, give number')
and if not an int was given it is wrong so you can state that the input is wrong. You could do the same for your initial n = int(input("How many numbers do you want to check:")) call, this will fail if it cannot evaluate to an int successfully and crash your program.