How to insert number every nth letter in a string in Python? - python

I'm writing a program to encrypt a string input. I have a random number generator, and some code that converts the random number into a letter. How would I go about inserting this letter after every say, 3rd letter? I.e. String before: abcdef , String after: abcldefk.
Code for the random number generator if it helps:
Letter = random.randrange(1,26)
print chr(Letter + ord('A'))

You can use str.join, enumerate with a start index equal to 1 and modulo:
print("".join([x if i % 3 else x + random_letter for i, x in enumerate(s,1)]))
If you just want to insert a random letter, you can use string.ascii_letters and random.choice:
from random import choice
from string import ascii_letters
s = "abcdef"
print("".join([x if i % 3 else x + choice(ascii_letters) for i, x in enumerate(s,1)])
abcQdefN

I was inspired by Padraic's answer and wanted to add a little bit more.
import random
Letter = random.randrange(1,26)
def encrypt_string(string, n):
return ("".join([x if i % n else chr(Letter + ord('A')) for i, x in enumerate(string)]))
Here is a string "encryption" (using it loosely) method for every 'nth' letter.
Results (Answers may vary due to random):
print(encrypt_string("0123456789", 2)) # Every other letter
M1M3M5M7M9
print(encrypt_string("0123456789", 3)) # Every third letter
D12D45D78D
I hope this helped.

Related

What wrong with this code: first appearance of a word

I wrote a program (appear) that keeps generating random letters, from a to z, till a given word appears:
import random
def appear(word):
word = list(word)
w = word
l = list('abcdefghijklmnopqrstuvwxyz')
i = 0
while len(w) > 0:
r = int(random.random() * 26)
print(l[r], end='')
if (w[0] == l[r] and i == 1) or (w[0] == l[r] and len(w) == len(word)):
i = 1
del w[0]
else:
i = 0
w = word
For example, appear('car') should produce: ajzkcar.
I tried printing in each loop the value of w, and the problem seems to be that the program fails to reset w to the original word if it doesn't find two consecutive letters, even though I clearly say that it should in the last "else"
I suggest to not delete anything but keep track of the string you have output so far, trim it to the length of word and then check if it actually is word:
import random
def appear(word):
l = list('abcdefghijklmnopqrstuvwxyz')
s = ""
while True:
r = int(random.random() * 26)
print(l[r], end='')
s += l[r] # keep track
s = s[-len(word):] # truncate
if s == word: # compare
return
appear("car")
You need to keep the letters that you have generated in memory, and compare them with the letters of the target word.
The word you're looking for has a fixed length. When you generate a new letter, you need to add that new letter to your memory at the right, and discard the oldest letter from your memory, at the left.
What data structure to use for this? Adding letters to the right and removing letters from the left, so that the total length remains fixed? I immediately think about a fixed-length queue.
The simplest way to get a fixed-length queue in python is to use collections.deque with a maxlen argument.
Also, to choose a letter, I have a preference for random.choice(letters) over letters[int(random.random() * 26)]
from collections import deque
from random import choice, choices
from string import ascii_lowercase as alphabet
def appear(word):
queue = deque(choices(alphabet, k=len(word)), maxlen=len(word))
target = deque(word)
print(''.join(queue), end='')
while queue != target:
new_letter = choice(alphabet)
queue.append(new_letter)
print(new_letter, end='')
appear('a')
# jca
appear('ab')
# zdoxkcnswafzsclmeduwhyhpdfwljujduwvbsxayihtfmlqrjxamlqnestzsncjjzbyfuzaczmuaiddfehckkrcnzfwwgnxfxcaifasaybokkxrqievmwqhisnaqhezcxwxfrstvuvwoedstpsrxkmxbubab

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

How to add a letter after every letter in a string?

I want to create an encryption script that encrypts the string given to it, here's how it went.
# First, I created a list of the string I got
string = '16271'
string_list = []
for letter in string:
string_list.append(letter)
Then, I have a list called encrypt_list which the letters which I want to add in order to encrypt my string.
So, I use the following code to add a random letter from the encrypt_list after each letter/component in the string_list and then join the list and print as a string.
for i in range(0, len(string) - 1):
string_list.insert(for letter in string_list: string_list.index(letter) + 1, encrypt_list[random.randint(0, len(encrypt_list) - 1)])
print("The encrypted string is: ")
print(''.join(string_list))
I expected the output to be: 1A6b2n781 (I bolded the letter to show my actual string in it) But I am getting an error, that I cannot use the for loop in the insert function, and I cannot find another way of doing that, please help. Hope I make my problem clear
Not sure what your encrypted_list looks like, but if it's a list of letters, this would work:
import random
string = '16271'
encrypted_list = ['r', 't', 's', 'o', 'j', 'e']
encrypted_string = ''.join([s + random.choice(encrypted_list) for s in string])
Something like this?
# First, I created a list of the string I got
import random
string = '16271'
string_list = []
for letter in string:
string_list.append(letter)
the_other_list = ['lorem', 'dorem', 'forem', 'borem']
for i in range(0, len(the_other_list)):
the_other_list[i] = string_list[random.randint(0, len(string_list) - 1)] + the_other_list[i]
print(''.join(the_other_list))
Result example: 1lorem2dorem2forem7borem
You can use a for loop, adding one letter to the list at a time, then adding a randomly selected letter immediately afterwards (if we're not processing the last letter in the list). I've used constants from string to define the space of characters to sample from; you can adjust this as you see fit.
This should be simpler than trying to do repeated insertion in the middle of the list (where you'd have to handle memory shifting as you're inserting, plus it'd get slower for larger texts because you'd be attempting to insert in the middle of a list).
# First, I created a list of the string I got
import random
import string
encrypt_text = string.ascii_uppercase + string.ascii_lowercase + string.digits
plaintext = '16271'
letters = []
for index, letter in enumerate(plaintext):
letters.append(letter)
if index != len(plaintext) - 1:
letters.append(random.choice(encrypt_text))
print("The encrypted string is: ")
print(''.join(letters))
Based on how you defined the problem, I would recommend implementing it as a generator:
import random
import string
def _gen_string(s):
alphabet = string.ascii_letters
for c in s:
yield c
yield random.choice(alphabet)
Then you can use that as the basis for your encryption:
def encrypt(s):
return ''.join(_gen_string(s))
encrypt('16271')
# 1J6P2U7Z1i
Of course, this is not really encryption. It's obscurity and obscurity is not a form of security that should be relied upon :-)

Shifting all the alphabets of a string by a certain step

input: ['baNaNa', 7] # string and step size
required output : 'utGtGt' # every character of string shifted backwards by step size
import ast
in_string = input()
lis = ast.literal_eval(in_string)
st = lis[0]
step = lis[1]
alphabets = 'abcdefghijklmnopqrstuvwxyz'
password = ''
for letter in st:
if letter in alphabets:
index_val = alphabets.index(letter) - (step)
password += alphabets[index_val]
print(password)
Output i am getting is 'utgtgt'. I want 'utGtGt'. Help on this would be appreciated a lot.
The string module has methods to create a transformation dictionary and a translate method to do exactly what you want:
st = "baNaNa"
step = 7
alphabets = 'abcdefghijklmnopqrstuvwxyz'
alph2 = alphabets.upper()
# lower case translation table
t = str.maketrans(alphabets, alphabets[-step:]+alphabets[:-step])
# upper case translation table
t2 = str.maketrans(alph2, alph2[-step:]+alph2[:-step])
# merge both translation tables
t.update(t2)
print(st.translate(t))
Output:
utGtGt
You give it the original string and an equal long string to map letters to and apply that dictionary using str.translate(dictionary).
The sliced strings equate to:
print(alphabets)
print(alphabets[-step:]+alphabets[:-step])
abcdefghijklmnopqrstuvwxyz
tuvwxyzabcdefghijklmnopqrs
which is what your step is for.
See Understanding slice notation if you never saw string slicing in use.
by processing each charater and checking it's cardinal no and making calculation accordingly help you to reach the result
def func(string, size):
if size%26==0:
size=26
else:
size=size%26
new_str = ''
for char in string:
if char.isupper():
if ord(char)-size<ord('A'):
new_str+=chr(ord(char)-size+26)
else:
new_str+=chr(ord(char)-size)
elif char.islower():
if ord(char)-size<ord('a'):
new_str+=chr(ord(char)-size+26)
else:
new_str+=chr(ord(char)-size)
return new_str
res =func('baNaNa', 7)
print(res)
# output utGtGt
Here's a simple solution that makes use of the % modulo operator to shift letters backwards.
It basically collects all of the letters in a reverse index lookup dictionary, so looking up letter positions is O(1) instead of using list.index(), which is linear O(N) lookups.
Then it goes through each letter and calculates the shift value from the letter index e.g. for the letter a with a shift value of 7, the calculation will be (0 - 7) % 26, which will give 19, the position of u.
Then once you have this shift value, convert it to uppercase or lowercase depending on the case of the original letter.
At the end we just str.join() the result list into one string. This is more efficient than doing += to join strings.
Demo:
from string import ascii_lowercase
def letter_backwards_shift(word, shift):
letter_lookups = {letter: idx for idx, letter in enumerate(ascii_lowercase)}
alphabet = list(letter_lookups)
result = []
for letter in word:
idx = letter_lookups[letter.lower()]
shifted_letter = alphabet[(idx - shift) % len(alphabet)]
if letter.isupper():
result.append(shifted_letter.upper())
else:
result.append(shifted_letter.lower())
return ''.join(result)
Output:
>>> letter_backwards_shift('baNaNa', 7)
utGtGt
I would probably go with #Patrick Artner's pythonic solution. I just showed the above implementation as a learning exercise :-).

Generate a random string with a random number of letters and spaces

I have written a function that returns a random string of length n.
import string, random
def randomString(N):
return ''.join(random.sample(string.ascii_lowercase + ' ', N))
However, this only ever returns a string with one of each letter/space. I need a string with a random number of lowercase letters and spaces (characters can repeat).
I have tried adding another argument to the .join method and it returns a syntax error.
How can I change this function to produce a random number of letters and spaces?
from random import choice
from string import ascii_lowercase
# vary the number of spaces appended to adjust the probability
chars = ascii_lowercase + " " * 10
def random_string(n):
return "".join(choice(chars) for _ in range(n))
then
>>> print(random_string(15))
fhr qhay nuf u
As with the number of spaces, you can adjust the number of times each char appears to change its relative probability:
chars = (
' !,,,,,--....'
'.....:;aaaaaaaaaaaaaaaaaaaaabbbbbcccccccccdddddddddeeeeeeeee'
'eeeeeeeeeeeeeeeeeeeefffffggggghhhhhhhhhiiiiiiiiiiiiiiiiiiijj'
'klllllllllmmmmmmnnnnnnnnnnnnnnnnnnooooooooooooooooppppppwrrr'
'rrrrrrrrrrrrrssssssssssssssssttttttttttttttttttttuuuuuuuvvvw'
'wwxyyyyz'
)
for _ in range(5):
print(random_string(30))
gives
sxh ehredi clo-ioodmttlpoir.wo
ijr thc -o,iepe.pcicfrn.osui.a
et rtl teektet rrecyd.d .bate
aji ueava hahe arv tgnrnt eecs
a ne:tudsdu,nlnhbeirp,oioitt e
You're looking for random.choice
import string, random
def randomString(N):
return ''.join(random.choice(string.ascii_lowercase + ' ') for i in range(N))
You can very easily do this with a simple loop, using random.choice rather than random.sample to do it all at once:
>>> import string, random
>>> def random_string(n):
... count = 0
... s = ''
... while count < n:
... s += random.choice(string.ascii_lowercase + ' ')
... count += 1
... return s
...
>>> random_string(27)
'amwq frutj nq dbotgllrbmhnj'
>>> random_string(27)
'khjnmhvgzycqm vyjqcttybuqm '
>>> random_string(27)
'ssakcpeesfe kton gigblmgo o'

Categories

Resources