How to randomly change n characters in a string - python

I am wondering how to randomly change n characters in a string, e.g.
orig = 'hello'
mod = 'halle'
that I want to randomly select two positions (orig[1] and orig[4]) in the string, and replace the chars in the positions of the original string (hello) with randomly selected chars (a and e here), results in a new string halle.

import random
import string
orig='hello'
char1=random.choice(string.ascii_lowercase) #random character1
char2=random.choice(string.ascii_lowercase) #random character2
while char1 == char2: # #check if both char are equal
char2=random.choice(string.ascii_lowercase)
ran_pos1 = random.randint(0,len(orig)-1) #random index1
ran_pos2 = random.randint(0,len(orig)-1) #random index2
while ran_pos1 == ran_pos2: #check if both pos are equal
ran_pos2 = random.randint(0,len(orig)-1)
orig_list = list(orig)
orig_list[ran_pos1]=char1
orig_list[ran_pos2]=char2
mod = ''.join(orig_list)
print(mod)

If you just want to change the different characters at random index in a string the below function will help. This script will ask for the input string(i.e., word) and the total places/ indexes ((i.e.,)value or 'n' places) you need to change with random characters, and this will print the modified string as needed.
import random
import string
# Method to change N characters from a string with random characters.
def randomlyChangeNChar(word, value):
length = len(word)
word = list(word)
# This will select the two distinct index for us to replace
k = random.sample(range(0,length),value)
for index in k:
# This will replace the characters at the specified index with
# the generated characters
word[index] = random.choice(string.ascii_lowercase)
# Finally print the string in the modified format.
print("" . join(word))
# Get the string to be modified
string_to_modify = raw_input("Enter the string to be replaced...\n")
# get the number of places that needed to be randomly replaced
total_places = input("Enter the total places that needs to be modified...\n")
# Function to replace 'n' characters at random
randomlyChangeNChar(string_to_modify, total_places)
Output
Enter the string to be replaced...
Hello
Enter the total places that needs to be modified...
3
Hcado

Related

I want to duplicate a random letter of a string 1 time. How can I do?

This is my string:
keyword = "qatarworldcup"
I mean my string should be qqatarworldcup, qatarworldcupp or qatarrworlddcup
This should be pretty easy to do if you break it up into parts.
Select a random letter from the word.
import random
letter_index = random.randint(0, len(keyword)-1)
Split the word into two parts at the letter you picked.
before, after = keyword[:letter_index], keyword[letter_index:]
Join the two parts, adding an extra instance of the selected letter
result = before + keyword[letter_index] + after
If your strings are big enough, or you're doing this multiple times, you could see a speedup from reducing the number of string concatenations, because that's an O(N) operation on account of the immutability of strings. Since the selected letter already exists in the word, you can split it such that the selected letter is the last character of before and the first character of after. Then, you only need a single concatenationThanks to #Mechanic Pig for your comment:
before, after = keyword[:letter_index+1], keyword[letter_index:]
result = before + after
from random import randint
keyword = "qatarwordcup"
idx = randint(0, len(keyword) - 1)
keyword = keyword[:idx] + keyword[idx] + keyword[idx:]
I'd do it like this
import random
#Find random position in string
r = random.randint(0, len(keyword) - 1)
#Create new string with added character at random position
newStr = keyword[:r] + keyword[r] + keyword[r:]
Iteration through index-character pairs, apply the condition on each "term" with the ternary operator and join everything together.
import random
# fix random number generator (for testing only!)
random.seed(190)
keyword = "qatarworldcup"
# random index
r = random.randint(0, len(keyword)-1)
out = ''.join(char * 2 if i == r else char for i, char in enumerate(keyword))
print(out)
#qaatarworldcup

split a string to have chunks containing the maximum number of possible characters

e.g. string = 'bananaban'
=> ['ban', 'anab', 'an']
My attempt:
def apart(string):
letters = []
for i in string:
while i not in letters:
letters.append(i)
print("The letters are:" +str(letters))
x = []
result = []
return result
string = str(input("Enter string: "))
print(apart(string)
Basically, If I know all the letters that are in the word/string, I want to add them into x, until x contains all letters. Then I want to add x into result.
In my examaple "bananaban" it would mean [ban] is one x, because "ban" countains the letter "b","a" and "n". Same goes for [anab]. [an] only contains "a" and "n" because it is the end of the word.
Would be cool if somebody could help me ^^
IIUC, you want to split after all characters are in the current chunk.
You could use a set to keep track of the seen characters:
s = 'bananaban'
seen = set()
letters = set(s)
out = ['']
for c in s:
if seen != letters:
out[-1] += c
seen.add(c)
else:
seen = set(c)
out.append(c)
output: ['ban', 'anab', 'an']
The logical way seens to be first create a set with all letters in your string, then go over teh original one, collecting each character, and startign a new collection each time the set of letters in the collection match the original.
def apart(string):
target = set(string)
result = []
component = ""
for char in string:
component += char
if set(component) == target:
result.append(component)
component = ""
if component:
result.append(component)
return result
Using a set of the characters in the string, you can loop through the string and add or extend the last group in your resulting list:
S = "bananaban"
chars = set(S) # distinct characters of string
groups = [""] # start with an empty group
for c in S:
if chars.issubset(groups[-1]): # group contains all characters
groups.append(c) # start a new group
else:
groups[-1] += c # append character to last group
print(groups)
['ban', 'anab', 'an']

Scrabble cheater: scoring wildcard characters to zero in Python

I'm new to python world, and I made a code of scrabble finder with two wildcards (* and ?) in it. When scoring the word, I would like to score wildcard letters to zero, but it looks like it doesn't work. I'm wondering what is missing here.
When you look into the line after "# Add score and valid word to the empty list", I tried to code if a letter in the word is not in the rack, I removed the letter so that I can only score other characters that are not coming from wildcards and matches with the letter in the rack. For example, if I have B* in my rack and the word is BO, I would like to remove O and only score B so that I can score wildcard to zero.
But the result is not what I expected.
import sys
if len(sys.argv) < 2:
print("no rack error.")
exit(1)
rack = sys.argv[1]
rack_low = rack.lower()
# Turn the words in the sowpods.txt file into a Python list.
with open("sowpods.txt","r") as infile:
raw_input = infile.readlines()
data = [datum.strip('\n') for datum in raw_input]
# Find all of the valid sowpods words that can be made
# up of the letters in the rack.
valid_words = []
# Call each word in the sowpods.txt
for word in data:
# Change word to lowercase not to fail due to case.
word_low = word.lower()
candidate = True
rack_letters = list(rack_low)
# Iterate each letter in the word and check if the letter is in the
# Scrabble rack. If used once in the rack, remove the letter from the rack.
# If there's no letter in the rack, skip the letter.
for letter in word_low:
if letter in rack_letters:
rack_letters.remove(letter)
elif '*' in rack_letters:
rack_letters.remove('*')
elif '?' in rack_letters:
rack_letters.remove('?')
else:
candidate = False
if candidate == True:
# Add score and valid word to the empty list
total = 0
for letter in word_low:
if letter not in rack_letters:
word_strip = word_low.strip(letter)
for letter in word_strip:
total += scores[letter]
valid_words.append([total, word_low])
I'm going to go a slightly different route with my answer and hopefully speed the overall process up. We're going to import another function from the standard library -- permutations -- and then find possible results by trimming the total possible word list by the length of the rack (or, whatever argument is passed).
I've commented accordingly.
import sys
from itertools import permutations # So we can get our permutations from all the letters.
if len(sys.argv) < 2:
print("no rack error.")
exit(1)
rack = sys.argv[1]
rack_low = rack.lower()
# Turn the words in the sowpods.txt file into a Python list.
txt_path = r'C:\\\\\sowpods.txt'
with open(txt_path,'r') as infile:
raw_input = infile.readlines()
# Added .lower() here.
data = [i.strip('\n').lower() for i in raw_input]
## Sample rack of 7 letters with wildcard character.
sample_rack = 'jrnyoj?'
# Remove any non-alphabetic characters (i.e. - wildcards)
# We're using the isalpha() method.
clean_rack = ''.join([i for i in sample_rack if i.isalpha()])
# Trim word list to the letter count in the rack.
# (You can skip this part, but it might make producing results a little quicker.)
trimmed_data = [i for i in data if len(i) <= len(clean_rack)]
# Create all permutations from the letters in the rack
# We'll iterate over a count from 2 to the length of the rack
# so that we get all relevant permutations.
all_permutations = list()
for i in range(2, len(clean_rack) + 1):
all_permutations.extend(list(map(''.join, permutations(clean_rack, i))))
# We'll use set().intersection() to help speed the discovery process.
valid_words = list(set(all_permutations).intersection(set(trimmed_data)))
# Print sorted list of results to check.
print(f'Valid words for a rack containing letters \'{sample_rack}\' are:\n\t* ' + '\n\t* '.join(sorted(valid_words)))
Our output would be the following:
Valid words for a rack containing letters 'jrnyoj?' are:
* jo
* jor
* joy
* no
* nor
* noy
* ny
* on
* ony
* or
* oy
* yo
* yon
If you want to verify that the results are actually in the sowpods.txt file, you can just index the sowpods.txt list by where the word you want to look up is indexed:
trimmed_data[trimmed_data.index('jor')]
When you are totalling the scores you are using the words from the wordlist and not the inputted words:
total=0
for letter in word_low:
...
Rather, this should be:
total=0
for letter in rack_low:
...
Also, You do not need to loop and remove the letters with strip at the end.
you can just have:
total = 0
for letter in rack_low:
if letter not in rack_letters:
try:
total += scores[letter]
except KeyError: # If letter is * or ? then a KeyError occurs
pass
valid_words.append([total, word_low])

Please could you explain this code, line 8 in particular ; the one with the loop in it?

An explanation would mightily help. In particular the line with the loop
import string
from random import *
letters = string.ascii_letters
digits = string.digits
symbols = string.punctuation
chars = letters + digits + symbols
min_length = 8
max_length = 16
password = "".join(choice(chars) for x in range(randint(min_length, max_length)))
print(password)
import string
from random import *
#Strings of ascii letters, digits, and punctuation
letters = string.ascii_letters
digits = string.digits
symbols = string.punctuation
#A string combining letters, digits and symbols
chars = letters + digits + symbols
min_length = 8
max_length = 16
#In the range of a random integer between min_length and max_length...
#Choose a random character from the string chars...
#And join the list containing those random characters into one string
password = "".join(choice(chars) for x in range(randint(min_length, max_length)))
print(password)
This is an equivalent to the line with the for. Hope this helps.
# We will temporally store the password character in this list
password_chars = []
# Choose a random length for the password
password_length = randint(min_length, max_length)
# Choose `password_length` random chars for the password
for x in range(password_length):
# Randomly choose a character from the valid password characters
random_valid_character = choice(chars)
# Add the random valid character to the password characters list
password_chars.append(random_valid_character)
# Join the password character list to form a string
password = ''.join(password_chars)
The code you provided uses list comprehension to write the same loop in a shorter way, sacrificing readability for shortness (one could argue).
LINE BY LINE
import string: Imports the string module
from random import *: Imports everything from the random module
letters = string.ascii_letters: Stores in a list all ascii letters
digits = string.digits: Stores in a list all digist (0-9)
symbols = string.punctuation: Stores in a list all punctuation marks
chars = letters + digits + symbols: Joins the last three lists
min_length = 8: Sets the minimum password length to 8
max_length = 16: Sets the maximum password length to 16
password = "".join(choice(chars) for x in range(randint(min_length, max_length))): This one is trickier.
randint(min_length, max_length) returns and integer between the minimum and maximum length
range() returns a list like [0,1,2... x-1] where x is the length of the password from the previous part
for x in range cycles through each item in the previous list of integers [0,1,2... x-1], so, in short, one cycle per character in the password
choice(chars) chooses a character randomly from the list chars
"".join(). Not ethat, by this point, we have a list of characters chosen randomly, with a length between 8 and 16. Join basically puts all the characters together in a string, sepparated by "" (empty string, so it puts them together)
The entire code is actually a basic code for creating passwords.
To create a password , we first need the elements of it viz digits , alphabets , characters.
Once we have the units ready , the code defines the maximum and the minimum length of the password
Finally , in the for loop part , the code generates a list of random length between the max_length and min_length.
So, each time you run , a new password of different length gets created.

Alphabet to integers

I'm trying to create a programm in which a user inputs a string e.g 'roller' and the program converts the alphabet to numbers such as a=1, b=2, c=3 etc, and the calculate the sum of these values. But, if the program finds two same letters in a row then it doubles the sum. So far I have done this:
input = raw_input('Write Text: ')
input = input.lower()
output = []
sum=0
for character in input:
number = ord(character) - 96
sum=sum+number
output.append(number)
print sum
which calculates the sum of the characters and also appends the converted characters to a new array. So can anyone help me to double the sum if two letters appear in a row?
Store the previous character and compare it to the current character. If they're the same, double the value.
word = 'hello'
out = []
c_prev = None
for c in word:
value = ord(c) - ord('a')
if c == c_prev: # double if repeated character
value = value * 2
out.append(value)
c_prev = c # store for next comparison
print(sum(out))

Categories

Resources