How do I replace characters in a string in Python? - python

I'm trying to find the best way to do the following:
I have a string lets say:
str = "pkm adp"
and I have a certain code in a dictionary to replace each charecter such as this one:
code = {'a': 'c', 'd': 'a', 'p': 'r', 'k': 'e', 'm': 'd'}
('a' should be replaced by 'c', 'd' by 'a' ...)
How can I convert the first string using the required characters from the dictionary to get the new string? Here for example I should get "red car" as the new string.

Try this:
>>> import string
>>> code = {'a': 'c', 'd': 'a', 'p': 'r', 'k': 'e', 'm': 'd'}
>>> trans = string.maketrans(*["".join(x) for x in zip(*code.items())])
>>> str = "pkm adp"
>>> str.translate(trans)
'red car'
Explanation:
>>> help(str.translate)
Help on built-in function translate:
translate(...)
S.translate(table [,deletechars]) -> string
Return a copy of the string S, where all characters occurring
in the optional argument deletechars are removed, and the
remaining characters have been mapped through the given
translation table, which must be a string of length 256.
>>> help(string.maketrans)
Help on built-in function maketrans in module strop:
maketrans(...)
maketrans(frm, to) -> string
Return a translation table (a string of 256 bytes long)
suitable for use in string.translate. The strings frm and to
must be of the same length.
The maketrans line turns the dictionary into two separate strings suitable for input into maketrans:
>>> code = {'a': 'c', 'd': 'a', 'p': 'r', 'k': 'e', 'm': 'd'}
>>> code.items()
[('a', 'c'), ('p', 'r'), ('k', 'e'), ('m', 'd'), ('d', 'a')]
>>> zip(*code.items())
[('a', 'p', 'k', 'm', 'd'), ('c', 'r', 'e', 'd', 'a')]
>>> ["".join(x) for x in zip(*code.items())]
['apkmd', 'creda']

"".join(code.get(k, k) for k in str)
would also work in your case.
code.get(k, k) returns code[k] if k is a valid key in code; if it isn't, it returns k itself.

>>> s = "pkm adp"
>>> code = {'a': 'c', 'd': 'a', 'p': 'r', 'k': 'e', 'm': 'd'}
>>> from string import maketrans
>>> s.translate(maketrans(''.join(code.keys()), ''.join(code.values())))
'red car'

though it would be tedious but a quick fix is str.replace("old", "new"). Here is the documentation for your help too http://www.tutorialspoint.com/python/string_replace.htm

Assuming you are using Python 2.x:
>>> from string import translate, maketrans
>>> data = "pkm adp"
>>> code = {'a': 'c', 'd': 'a', 'p': 'r', 'k': 'e', 'm': 'd'}
>>> table = maketrans(''.join(code.keys()), ''.join(code.values()))
>>> translate(data, table)
'red car'

>>>print ''.join([code.get(s,s) for s in str])
'red car'

Related

Creating a word-translator application in Python 3. Any "Best practices"?

I am trying to write a code that translates English into the Chef's(from the muppet show) language
it should change these letters/sounds into the other language
Input Output
tion shun
an un
th z
v f
w v
c k
o oo
i ee
I have to write a function (def) that converts it so that it will print the new language
print(eng2chef('this is a chicken'))
should return
zees ees a kheekken
my code so far is:
help_dict = {
'tion': 'shun',
'an': 'un',
'th': 'z',
'v': 'f',
'w': 'v',
'c': 'k',
'o': 'oo',
'i': 'ee',
}
def eng2chef(s):
s.split()
for i in s:
if i in help_dict:
i = help_dict[i]
print(i)
eng2chef('this is a chicken')
but this only changes certain letters and then prints those letters
ee
ee
k
ee
k
Can someone please Help!!
You can do this by iteratively replace strings:
help_dict = [
('tion', 'shun'),
('an', 'un'),
('th', 'z'),
('v', 'f'),
('w', 'v'),
('c', 'k'),
('o', 'oo'),
('i', 'ee')
]
def eng2chef(s):
for x, y in help_dict:
s = s.replace(x,y)
return s
But note that I changed your dict into a list so that the replacement order is enforced. This is critical because you do not want to replace 'w' into 'v' then replace 'v' into 'f', only the other way round.
Your code splits each character making it to target only single letters and change them.
help_dict = {
'tion': 'shun',
'an': 'un',
'th': 'z',
'v': 'f',
'w': 'v',
'c': 'k',
'o': 'oo',
'i': 'ee',
}
def eng2chef(word):
new_word = word
for key in help_dict.keys():
new_word = word.replace(key, help[key])
print(new_word)
eng2chef('this is a chicken')
Output : zees ees a kheeken
This targets all the words in the passed in input that are found in the dictionary, replacing them with values given.
I hope this helps.

function that creates a new words by given pattern

im trying to create a function that takes a word (capital letters and lowercase letters) and map each character to a new character. the pattern is each vowel (AEIOU) becomes the next vowel in order (A -> E, E - > I). For constant letters becomes the thirds letter (B -> F, C -> G)
>>>'hello'
'lippu'
>>> 'today'
'xuhec'
>>> 'yesterday'
'ciwxivhec'
I know that i would have to create two lists:
vowels = ['a', 'e', 'i', 'o', 'u']
constants = ['b', 'c','d','f','g','h','j','k','l','m','n','p', 'q','r', 's','t','v','w','x','y', 'z']
and uses the index() function, to check the current index and add 3 to it, but im stuck after that.
Letters loop back around for cases that extend beyond the list. (x-z, and u)
To compute the maps you can use enumerate (to get the index of the current) together with modulo (for the indices greater than the list length), something like this:
vowels = ['a', 'e', 'i', 'o', 'u']
consonants = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z']
vowels_map = {k: vowels[(i + 1) % len(vowels)] for i, k in enumerate(vowels)}
consonants_map = {k: consonants[(i + 3) % len(consonants)] for i, k in enumerate(consonants)}
print(vowels_map)
print(consonants_map)
Output
{'u': 'a', 'a': 'e', 'o': 'u', 'e': 'i', 'i': 'o'}
{'s': 'w', 'z': 'd', 'v': 'y', 'm': 'q', 'f': 'j', 'h': 'l', 'd': 'h', 'g': 'k', 'q': 't', 'n': 'r', 'p': 's', 'k': 'n', 't': 'x', 'y': 'c', 'r': 'v', 'w': 'z', 'x': 'b', 'l': 'p', 'b': 'f', 'j': 'm', 'c': 'g'}
Note that dictionaries have no order, that being said you could use them in the following way:
def replace_from_dict(word, table):
return ''.join(table[c] for c in word)
words = ['hello',
'today',
'yesterday']
for word in words:
print(replace_from_dict(word, { **vowels_map, **consonants_map }))
Output (from using replace_from_dict)
lippu
xuhec
ciwxivhec
We can use itertools.cycle. First check which category i belongs to either vowel or consonants (not constant). Then create a cycle from that respective list, use while and next until we are at the corresponding letter. If its a vowel we simply append the next value, if its a consonant we advance 2 positions and then append the next value. After use .join() to convert back to string.
from itertools import cycle
vwl = ['a', 'e', 'i', 'o', 'u']
cnst = ['b', 'c','d','f','g','h','j','k','l','m','n','p', 'q','r', 's','t','v','w','x','y', 'z']
s = 'hello'
new = []
for i in s.lower():
if i in vwl:
a = cycle(vwl)
while i != next(a):
next(a)
new.append(next(a))
if i in cnst:
b = cycle(cnst)
while i != next(b):
next(b)
for x in range(2):
next(b)
new.append(next(b))
res = ''.join(new)
print(res)
# lippu
Works for words that include edge letters, zumba produces daqfe
I have defined two dictionaries for edge cases, vowel_dictionary, and a dictionary for letters x/y/z to achieve wrapping. I iterated through the string and if the character is a special character, I use the appropriate dictionary to find the word. However if the character is below 'w' and not a vowel, I just add 4 to its ord value (ASCII value) and convert it char.
def transform(input):
return_string = ""
vowel_dictionary = {
'a': 'e',
'e': 'i',
'i': 'o',
'o': 'u',
'u': 'a'
}
edge_dictionary = {
'x': 'b',
'y': 'c',
'z': 'd'
}
for character in input.lower():
if character in vowel_dictionary:
return_string += vowel_dictionary[character]
elif ord(character) <= ord("v"):
return_string += chr(ord(character) + 4)
else :
return_string += edge_dictionary[character]
return return_string
I have ran a few tests with the code above:
Tests
transform("hello") # => lippu
transform("today") # => xuhec
transform("yesterday") # => ciwxivhec

'str' object is not callable in caesar encryptor

def encrypt_caesar(plaintext):
s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
d = dict(map(s,s[3:]+ s[:3]))
return ''.join(map(lambda l: d.get(l,l), plaintext.lower()))
Tried to copy this code from Stanford lecture slide and run it but it gives 'str' object is not callable error, what am I doing wrong?
I guess the author of the slide didn't actually test the code.
The code you produced is trying to use map() to call s as a function:
map(s,s[3:]+ s[:3])
# ^ This must be a *callable object*, like a function
If you wanted to create a dictionary mapping ASCII letters to a letter 3 spots along in the alphabet, use the zip() function instead:
d = dict(zip(s, s[3:] + s[:3]))
zip() then pairs up each element in s with each element in s[3:] + s[:3], and those (letter, letter + 3) pairs are then passed to dict() to form key-value pairs:
>>> s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
>>> dict(zip(s, s[3:] + s[:3]))
{'A': 'D', 'I': 'L', 'L': 'O', 'X': 'A', 'N': 'Q', 'D': 'G', 'S': 'V', 'B': 'E', 'V': 'Y', 'C': 'F', 'K': 'N', 'W': 'Z', 'R': 'U', 'O': 'R', 'T': 'W', 'P': 'S', 'F': 'I', 'J': 'M', 'M': 'P', 'E': 'H', 'Q': 'T', 'H': 'K', 'G': 'J', 'Z': 'C', 'U': 'X', 'Y': 'B'}
Next, your last line will completely fail to do any encryption, because your map only handles uppercase letters, but you lowercased your input. Either produce a lowercase map, or lowercase your input.
Lowercasing the map could look like this:
def encrypt_caesar(plaintext):
s = "abcdefghijklmnopqrstuvwxyz"
d = dict(zip(s, s[3:] + s[:3]))
return ''.join(map(lambda l: d.get(l, l), plaintext.lower()))
or you could just use the string.ascii_lowercase constant:
from string import ascii_lowercase
def encrypt_caesar(plaintext):
d = dict(zip(ascii_lowercase, ascii_lowercase[3:] + ascii_lowercase[:3]))
return ''.join(map(lambda l: d.get(l,l), plaintext.lower()))
Using this method is rather slow, however. For blazingly-fast 'encryption', use the str.translate() method; the input map for that is best produced with str.maketrans:
from string import ascii_lowercase as alc
def encrypt_caesar(plaintext, shift=3):
map = str.maketrans(alc, alc[shift:] + alc[:shift])
return plaintext.lower().translate(map)
I added a shift parameter to define how much of an alphabet shift should be applied.
I'll leave handling both lowercase and uppercase letters as an exercise to the reader!

Detecting if string iterator is a blank space

I'm attempting to write a small block of code that detects the most frequently occurring character. However, I've become stuck on not being able to detect if a value is blank space.
Below is the code I have:
text = "Hello World!"
## User lower() because case does not matter
setList = list(set(textList.lower()))
for s in setList:
if s.isalpha() and s != " ":
## Do Something
else:
setList.remove(s)
The problem is that set list ends with the following values:
[' ', 'e', 'd', 'h', 'l', 'o', 'r', 'w']
I've tried multiple ways of detecting the blank space with no luck, including using strip() on the original string value. isspace() will not work because it looks for at least one character.
The problem is, you are removing items from a list while iterating it. Never do that. Consider this case
['!', ' ', 'e', 'd', 'h', 'l', 'o', 'r', 'w']
This is how the setList looks like, after converting to a set and list. In the first iteration, ! will be seen and that will be removed from the setList. Now that ! is removed, the next character becomes the current character, which is . For the next iteration, the iterator is incremented and it points to e (since space is the current character). That is why it is still there in the output. You can check this with this program
num_list = range(10)
for i in num_list:
print i,
if i % 2 == 1:
num_list.remove(i)
pass
Output
0 1 3 5 7 9
But if you comment num_list.remove(i), the output will become
0 1 2 3 4 5 6 7 8 9
To solve your actual problem, you can use collections.Counter to find the frequency of characters, like this
from collections import Counter
d = Counter(text.lower())
if " " in d: del d[" "] # Remove the count of space char
print d.most_common()
Output
[('l', 3), ('o', 2), ('!', 1), ('e', 1), ('d', 1), ('h', 1), ('r', 1), ('w', 1)]
A short way is to first remove the spaces from the text
>>> text = "Hello world!"
>>> text = text.translate(None, " ")
>>> max(text, key=text.count)
'l'
This isn't very efficient though, because count scans the entire string once for each character (O(n2))
For longer strings it's better to use Collections.Counter, or Collections.defaultdict to do the counting in a single pass
How about removing the blank spaces before you start with lists and sets:
text = "Hello world!"
text = re.sub(' ', '', text)
# text = "Helloworld!"
the above answers are legitimate. you could also use the built-in count operator if you are not concerned with algorithmic complexity. For example:
## User lower() because case does not matter
text=text.lower()
num=0
most_freq=None
for s in text:
cur=text.count(s)
if cur>num:
most_freq=s
num=cur
else:
pass
How about using split(): it will fail if its blank space:
>>> [ x for x in text if x.split()]
['H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '!']
>>>
To count the duplicate:
>>> d = dict()
>>> for e in [ x for x in text if x.split()]:
... d[e] = d.get(e,0) + 1
...
>>> print d
{'!': 1, 'e': 1, 'd': 1, 'H': 1, 'l': 3, 'o': 2, 'r': 1, 'W': 1}
>>>
To get the single most frequent, use max:
text = "Hello World!"
count={}
for c in text.lower():
if c.isspace():
continue
count[c]=count.get(c, 0)+1
print count
# {'!': 1, 'e': 1, 'd': 1, 'h': 1, 'l': 3, 'o': 2, 'r': 1, 'w': 1}
print max(count, key=count.get)
# 'l'
If you want the whole shebang:
print sorted(count.items(), key=lambda t: (-t[1], t[0]))
# [('l', 3), ('o', 2), ('!', 1), ('d', 1), ('e', 1), ('h', 1), ('r', 1), ('w', 1)]
If you want to use Counter and use a generator type approach, you could do:
from collections import Counter
from string import ascii_lowercase
print Counter(c.lower() for c in text if c.lower() in ascii_lowercase)
# Counter({'l': 3, 'o': 2, 'e': 1, 'd': 1, 'h': 1, 'r': 1, 'w': 1})

How to print each letter in a string only once

Hello everyone I have a python question.
I'm trying to print each letter in the given string only once.
How do I do this using a for loop and sort the letters from a to z?
Heres what I have;
import string
sentence_str = ("No punctuation should be attached to a word in your list,
e.g., end. Not a correct word, but end is.")
letter_str = sentence_str
letter_str = letter_str.lower()
badchar_str = string.punctuation + string.whitespace
Alist = []
for i in badchar_str:
letter_str = letter_str.replace(i,'')
letter_str = list(letter_str)
letter_str.sort()
for i in letter_str:
Alist.append(i)
print(Alist))
Answer I get:
['a']
['a', 'a']
['a', 'a', 'a']
['a', 'a', 'a', 'a']
['a', 'a', 'a', 'a', 'a']
['a', 'a', 'a', 'a', 'a', 'b']
['a', 'a', 'a', 'a', 'a', 'b', 'b']
['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c']....
I need:
['a', 'b', 'c', 'd', 'e', 'g', 'h', 'i', 'l', 'n', 'o', 'p', 'r', 's', 't', 'u', 'w', 'y']
no errors...
Just check if the letter is not already in your array before appending it:
for i in letter_str:
if not(i in Alist):
Alist.append(i)
print(Alist))
or alternatively use the Set data structure that Python provides instead of an array. Sets do not allow duplicates.
aSet = set(letter_str)
Using itertools ifilter which you can say has an implicit for-loop:
In [20]: a=[i for i in itertools.ifilter(lambda x: x.isalpha(), sentence_str.lower())]
In [21]: set(a)
Out[21]:
set(['a',
'c',
'b',
'e',
'd',
'g',
'i',
'h',
'l',
'o',
'n',
'p',
's',
'r',
'u',
't',
'w',
'y'])
Malvolio correctly states that the answer should be as simple as possible. For that we use python's set type which takes care of the issue of uniqueness in the most efficient and simple way possible.
However, his answer does not deal with removing punctuation and spacing. Furthermore, all answers as well as the code in the question do that pretty inefficiently(loop through badchar_str and replace in the original string).
The best(ie, simplest and most efficient as well as idiomatic python) way to find all unique letters in the sentence is this:
import string
sentence_str = ("No punctuation should be attached to a word in your list,
e.g., end. Not a correct word, but end is.")
bad_chars = set(string.punctuation + string.whitespace)
unique_letters = set(sentence_str.lower()) - bad_chars
If you want them to be sorted, simply replace the last line with:
unique_letters = sorted(set(sentence_str.lower()) - bad_chars)
If the order in which you want to print doesn't matter you can use:
sentence_str = ("No punctuation should be attached to a word in your list,
e.g., end. Not a correct word, but end is.")
badchar_str = string.punctuation + string.whitespace
for i in badchar_str:
letter_str = letter_str.replace(i,'')
print(set(sentence_str))
Or if you want to print in sorted order you could convert it back to list and use sort() and then print.
First principles, Clarice. Simplicity.
list(set(sentence_str))
You can use set() for remove duplicate characters and sorted():
import string
sentence_str = "No punctuation should be attached to a word in your list, e.g., end. Not a correct word, but end is."
letter_str = sentence_str
letter_str = letter_str.lower()
badchar_str = string.punctuation + string.whitespace
for i in badchar_str:
letter_str = letter_str.replace(i,'')
characters = list(letter_str);
print sorted(set(characters))

Categories