No duplicate characters in string output - Python - python

What im making
Hi!
Im making a password generator script in Python ( Script below ). and i was wondering what the best way would be to make sure the passwords dont have two of the same character/symbol right after eachother.
as an example:
kjhd8!3JJp-#huwwg
i would like a way within my script to make sure the duplicates arent "touching". if that makes sense (my english isnt very good).
the same password can have the same character, thats fine. but i would like it not to have them "touching"
like:
kjwhd8!3Jp-#huwJg
if that makes sense.
The script
import random
import string
import sys
#amount of passwords to make
amount = 10
# Characters and symbols to use for the password
# ive split it up to make sure it takes from all of the lists
chars ="abcdefghjkmnpqrstuvwxyzABCDEFGHJK"
specials="#####!-----"
digits="2346789"
characters = list(chars + digits + specials)
def generate_random_password():
# length of the passwords
length = 18
# mixes and shuffles the characters
random.shuffle(characters)
# Puts the sections together at random
password = []
for i in range(length):
password.append(random.choice(characters) )
# another shuffle to make sure (probably noy needed but meh)
random.shuffle(password)
# converts to a string
print("".join(password))
# Prints out as many passswords as stated in the "amount" variable
for index in range(amount):
generate_random_password()

You can just check if the generated char is the same that the previous one, if it is: pick another char, else continue.
prev_char=None
for i in range(length):
random_char = random.choice(characters)
while prev_char == random_char:
random_char = random.choice(characters)
password.append(random_char)
prev_char = random_char

You can use a regex for this!
The expression:
(.)\1
What it does:
(.) - group that matches one character
\1 - reference to group 1 (the group above)
What this essentially does is that it looks for a character repeating right after itself.
How to use it?
import re
any(re.findall(r"(.)\1", "kjwhd8!3Jp-#huwJg"))
findall will find any ocurrences of this; any will give you True or False if there are any cases.
Note: You could also extend this so that the same character doesn't repeat within the next let's say 4 characters: (.).{0,4}\1

Related

python password generator loop problem print error

I trying to make a password generator using python. Currently, I just want the program to print random characters from the ascii table. I will later introduce numbers and symbols. I used a for loop to print random character from a range that the user inputs. It works however, when I use the end='' to print the characters on the same line a % shows up. I think it is there to show that it printed a no character. I would like the program to not print the % because later I will add other numbers and symbols.
I tried subtracting 1 from the range of number. What resulted was the same string with a % but 1 less than intended. I also tried creating a while loop that would print while the variable was less than the password number. It also printed the %.
Here is the code:
import random
import string
letters=string.ascii_letters
passwordnumber=int(input("How many characters do you want your password to be? "))
for i in range(passwordnumber):
print(random.choice(letters), end='')
The % print by your shell (may be zsh), it means the string not end by "\n". It's just a reminder from the shell. There is nothing wrong with you. You can just add a print() in the end of your code to print a "\n", and % will not show again.
Try this
characters = list(string.ascii_letters + string.digits + "!##$%^&*()")
def generate_random_password():
## length of password from the user
length = 8
## shuffling the characters
random.shuffle(characters)
## picking random characters from the list
password = []
for i in range(length):
password.append(random.choice(characters))
## shuffling the resultant password
random.shuffle(password)
## converting the list to string
## printing the list
return "".join(password)
Your script works absolutly fine in my side. see this https://onlinegdb.com/9EagkKVW1
If you feel like it's issue with end you can simply concat outputs to string and print at once like so.
import random
import string
letters=string.ascii_letters
pas =''
passwordnumber=int(input("How many characters do you want your password to be? "))
for i in range(passwordnumber):
pas += random.choice(letters)
print(pas)
outputs #
How many characters do you want your password to be? 5
AvfYm
we can use the random .sample() method. it requires 2 arguments:
- iterable of elements to use
- number of elements to take
the result does not contain duplicates.
import random
import string
letters=string.ascii_letters
passwordnumber=int(input("How many characters do you want your password to be? "))
pas = ''.join(random.sample(letters, k=passwordnumber))
print(pas)

Use randint and a limited number of Python tools to make the random numbers different and shuffle up a string

I'm learning Python from Brian Heinold's A Practical Introduction to Python Programming where one of the exercises in the Strings chapter reads as follows
An anagram of a word is a word that is created by rearranging the
letters of the original.
For instance, two anagrams of idle are deli and lied. Finding anagrams that are real words is beyond our reach until Chapter 12.
Instead, write a program that asks the user for a string and returns a
random anagram of the string—in other words, a random rearrangement of
the letters of that string.
The trick is we have not covered def and while yet, and the shuffle function has not been mentioned, which means we may not use it.
I have written a code which does the job except it often generates idential random numbers which is why the string does not get scrambled the way it is supposed to, e.g. if I punch in abc, I might get ccc or bba or aaa. Please advise how can I modify my code to make the random numbers different from one another? Thank you. Here is my code:
s = ''
string = input('Enter a word: ')
from random import randint
for i in range(len(string)):
randindex = randint(0,(len(string)-1))
#a = randindex
s = s + string[randindex]
#a += 1
# I tried to play with this additional variable.
# I wanted to write s = s + string[a] instead if the line
# that comes in between the comments.
# It did not work. Probably I need an individual cycle for that...
# I'm sure missing something.
print(s)
This isn't very efficient, but it is uniformly random, and for shortish words the inefficiency doesn't matter. Maybe it gives you an idea about how to do it better.
The idea is that we accumulate a new word (the anagram) by placing each letter in sequence at a random place in the new word. Python strings are immutable -- I'm sure your text covered that fact -- so in order to insert a letter, we need to make a new string consisting of the part before the random split point, the new letter, and then the part after the split point. We do that for each letter in the original, which is why this solution isn't very efficient.
from random import randint
word = input('Enter a word: ')
anagram = ''
for letter in word:
position = randint(0, len(anagram))
before = anagram[:position]
after = anagram[position:]
anagram = before + letter + after
print(anagram)

Python replace all characters in a string except for 3 characters with underscores

I'm working on a simple hangman app and I am trying to replace all the chars but three, in a word users have to guess, with underscores randomly.
So for example: America to A_M___C_
I have most of it down, but my code sometimes leaves more than 3 characters unconverted to underscores. Here is my code:
topics = {
"movie": ["Star-Trek", "Shang-Chi"],
"place": ["PARIS", "AMERICA", "ENGLAND"]
}
topic = random.choice(["movie", "place"])
solution = random.choice(topics[topic])
question = ""
length = len(solution)
underscores = length - 3
for char in solution:
for i in range(underscores):
add = question + random.choice([char, "_"])
question = question + add
Let's rehash your problem statement:
Given a string of unspecified length with more than three different characters, you want to keep three of these unique characters, and replace all the others.
Notice that the string could contain duplicates, so if your string is "abracadabra" and a is one of the letters you want to keep, that already gets you a__a_a_a__a.
import random
topics = {
"movie": ["Star-Trek", "Shang-Chi"],
"place": ["PARIS", "AMERICA", "ENGLAND"]
}
topic = random.choice(["movie", "place"])
solution = random.choice(topics[topic])
characters = set(solution)
keep = random.sample(list(characters), 3)
question = solution
for char in characters.difference(keep):
question = question.replace(char, '_')
set(solution) produces a set of the unique characters in the string, and random_sample(list(characters), 3) picks three of them (forcing the set back to a list is required to avoid a deprecation warning in Python >= 3.9). We then use the set.difference() to loop over the remaining unique characters, and replace all occurrences of them with underscores.
Your attempt doesn't normalize characters to upper or lower case; I would assume this is something you would actually want to do, but then probably normalize the questions to upper case already in the source. I'm leaving this as an excercise; this code simply regards a and A as different characters.
You have a few problems in your code. First of all the inner loop will restart for every character but that's not what you want. You want to put x underscores. Secondly, you only need to add your random choice, and not the while question. So, below a working program:
# get len(solution) - 3 unique numbers
indices = random.sample(range(len(solution)), len(solution) - 3)
question = list(solution) # convert to a list so we can index
for i in indices:
question[i] = "_" # change them to underscores
question = "".join(question) # convert to list to a string
The reasen your solution (and my previous solution) don't work is because the number of not underscores isn't limited. So you could keep a counter with the number of not underscores, and when that's equal to 3, only replace characters by underscores like this, but keep in mind you would still need to track the number of underscores. So this solution is better.
Here is one function that takes in a string and optional number to save letters, so 3 will save 3 letters, 5 will save 5 letters. There is no error check to see if save_letters is larger than the word and so forth. The code is supposed to show you exactly what is happening, not to be a clever one liner.
import random
def change_word(word, save_letters = 3):
length = len(word)
randies = []
ret = ""
while len(randies) < save_letters:
x = random.randint(0,length - 1)
if not x in randies:
randies.append(x)
for i in range(0, len(word)):
if i in randies:
ret += word[i]
continue
ret += "_"
return ret

How do I make it where the code ignores every symbol within a string except for those in a list?

I was trying to make a program that could be used for one-time pad encryption by counting the number of characters and having a random number for each one. I started making a line that would let the program ignore spaces, but then I realized I would also need to ignore other symbols. I had looked at How to count the number of letters in a string without the spaces? for the spaces,
and it proved very helpful. However, the answers only show how to remove one symbol at a time. To do what I would like by using that answer, I would have to have a long line of - how_long.count('character')'s, and symbols that I may not even know of may still be copied in. Thus, I am asking for a way where it will only count all the alphabetic characters I write down in a list. Is this possible, and if so, how would it be done?
My code:
import random
import sys
num = 0
how_long = input("Message (The punctuation will not be counted)\n Message: ")
charNum = len(how_long) - how_long.count(' ')
print("\n")
print("Shift the letters individually by their respective numbers.")
for num in range(0, charNum-1):
sys.stdout.write(str(random.randint(1, 25))+", ")
print(random.randint(1, 25))
If your desired outcome is to clean a string so it only contains a desired subset of characters the following will work but, I'm not sure I totally understand what your question is so you will probably have to modify somewhat.
desired_letters = 'ABCDOSTRY'
test_input = 'an apple a day keeps the doctor away'
cleaned = ''.join(l for l in test_input if l.upper() in desired_letters)
# cleaned == 'aaadaystdoctoraay'
Use Regex to find the number of letters in the input:
import re, sys, random
how_long = input("Message (The punctuation will not be counted)\n Message: ")
regex_for_letters = "[A-Za-z]"
letter_count = 0
for char in how_long:
check_letter = re.match(regex_for_letters, char)
if check_letter:
letter_count += 1
print(letter_count)
for num in range(0, letter_count-1):
sys.stdout.write(str(random.randint(1, 25))+", ")
print(random.randint(1, 25))
Filter the string:
source_string='My String'
allow_chars=['a','e','i','o','u'] #whatever characters you want to accept
source_string_list=list(source_string)
source_string_filtered=list(filter(lambda x: x in allow_chars,source_string_list))
the count would be: len(source_string_filtered)

How to use multiple 'if' statements nested inside an enumerator?

I have a massive string of letters all jumbled up, 1.2k lines long.
I'm trying to find a lowercase letter that has EXACTLY three capital letters on either side of it.
This is what I have so far
def scramble(sentence):
try:
for i,v in enumerate(sentence):
if v.islower():
if sentence[i-4].islower() and sentence[i+4].islower():
....
....
except IndexError:
print() #Trying to deal with the problem of reaching the end of the list
#This section is checking if
the fourth letters before
and after i are lowercase to ensure the central lower case letter has
exactly three upper case letters around it
But now I am stuck with the next step. What I would like to achieve is create a for-loop in range of (-3,4) and check that each of these letters is uppercase. If in fact there are three uppercase letters either side of the lowercase letter then print this out.
For example
for j in range(-3,4):
if j != 0:
#Some code to check if the letters in this range are uppercase
#if j != 0 is there because we already know it is lowercase
#because of the previous if v.islower(): statement.
If this doesn't make sense, this would be an example output if the code worked as expected
scramble("abcdEFGhIJKlmnop")
OUTPUT
EFGhIJK
One lowercase letter with three uppercase letters either side of it.
Here is a way to do it "Pythonically" without
regular expressions:
s = 'abcdEFGhIJKlmnop'
words = [s[i:i+7] for i in range(len(s) - 7) if s[i:i+3].isupper() and s[i+3].islower() and s[i+4:i+7].isupper()]
print(words)
And the output is:
['EFGhIJK']
And here is a way to do it with regular expressions,
which is, well, also Pythonic :-)
import re
words = re.findall(r'[A-Z]{3}[a-z][A-Z]{3}', s)
if you can't use regular expression
maybe this for loop can do the trick
if v.islower():
if sentence[i-4].islower() and sentence[i+4].islower():
for k in range(1,4):
if sentence[i-k].islower() or sentence[i+k].islower():
break
if k == 3:
return i
regex is probably the easiest, using a modified version of #Israel Unterman's answer to account for the outside edges and non-upper surroundings the full regex might be:
s = 'abcdEFGhIJKlmnopABCdEFGGIddFFansTBDgRRQ'
import re
words = re.findall(r'(?:^|[^A-Z])([A-Z]{3}[a-z][A-Z]{3})(?:[^A-Z]|$)', s)
# words is ['EFGhIJK', 'TBDgRRQ']
using (?:.) groups keeps the search for beginning of line or non-upper from being included in match groups, leaving only the desired tokens in the result list. This should account for all conditions listed by OP.
(removed all my prior code as it was generally *bad*)

Categories

Resources