switching letters to different letters inside a string (Caesar cipher) - python

I've got some homework involving Caesar cipher, and I got stuck here:
I need to write a function which gets a text (as a String) and a dictionary. The dictionary keys are the English ABC, and its values are other letters from the ABC.
My goal is to go over the text, and wherever there is a letter (only letters!)
change it to the value belongs to the specific letter in the dictionary.
edit: my function should return the deciphered text as a string.

You're looking for the translate method:
>>> u"abc".translate({ord('a'): u'x', ord('b'): u'y', ord('c'): u'z'})
'xyz'
Look at maketrans if you're using bytestrings or if your Python is older than 2.7.

A bit of pseudocode (language agnostic). You should be able to take it from here.
cipher = array
caesar_mask = [ A: G, ... , Z: F ]
for each letter_index in text
cipher_letter = caesar_mask[text[letter_index]]
cipher[] = cipher_letter
end

First question is if you have to do it in place.
Then I would look into these things:
list comprehension
map()
how to iterate through letters in string
how to join a sequence of letters to create string
how to replace characters in string
Not in any specific order and not necesarily all inclusive.

Related

Case-sensitive string word replacement from dictionary in Python

I have a dictionary full of key-value pairs where the key is a word I want to search for in a string and the value is what I want to replace it with. It needs to be able to preserve case as well. I'm stumbling over the logic in this circumstance.
I was thinking it would work to split the string up into a list of words, but I'm not sure if this would be the simplest way.
dict = {'my':'your', 'dog':'cat'}
string = 'My dog is named Jeffrey.'
I'd like to substitute the values in for the keys in the string, but maintain case and punctuation.
You may use the re.sub to make a substitution case insensitive. What is really difficult is to know what letter is capital because we may have words with different sizes, so I applied the rule that the first letter in the phrase has to be capital using capitalize method.
import re
dict = {'my':'your', 'dog':'cat'}
inputString = 'My dog is named Jeffrey.'
for key in dict.keys():
inputString = re.sub("(?i)"+key,dict[key],inputString)
inputString = inputString.capitalize()
print(inputString)

List Comprehension in a function

So I'm trying to write a function for a hangman game that will return a string that is composed of lowercase English letters - all lowercase English letters that are not in lettersGuessed. I can't see to get the list comprehension to work
def getAvailableLetters(lettersGuessed):
'''
lettersGuessed: list, what letters have been guessed so far
returns: string, comprised of letters that represents what letters have not
yet been guessed.
'''
[letterGuessed.remove(letter) if letter in'abcdefghijklmnopqrstuvwxyz' for letter in lettersGuessed ]
[letter for letter in 'abcdefghijklmnopqrstuvwxyz' if letter not in lettersGuessed]
To give more of an explanation as to why this works, it helps to consider and list comprehension as the following:
[ expression for item in list if conditional ]
In our case, list is the letters of the alphabet.
Our expression is simply the individual letter in the list and our conditional is if the letter does not already exist in lettersGuessed.
The nice thing is that it almost translates into an english sentence which should make it easy to understand.
Give me each letter in the alphabet if the letter is not in the list of guessed letters
I would recommend having a read through this article as having a good understanding of list comprehensions will be a huge benefit for your python coding.
https://www.pythonforbeginners.com/basics/list-comprehensions-in-python
Kind of expanding on #scoJo's response, here's my take.
import string
test_guesses = ['a','b','f']
def getAvailableLetters(lettersGuessed):
# Note that we're ensuring that input letters are lowercase when being compared to the list.
return ''.join([i for i in string.ascii_lowercase if i.lower() not in lettersGuessed])
With the original response, you were removing letters from the letters guessed list, not the alphabet.
My solution also taps into the string standard library of Python to create a list of letters without having to ensure that you've typed each one.
If you want to return a list, just remove the .join() function.
Input:
getAvailableLetters(test_guesses)
Output:
'cdeghijklmnopqrstuvwxyz'
For simplicity i'd propose using Python sets
A set is an "unordered collection of unique elements"
def getAvailableLetters(lettersGuessed):
# convert to set
all_letters_set = set('abcdefghijklmnopqrstuvwxyz')
letters_guessed_set = set(lettersGuessed)
# substract sets
available_letters = list(all_letters_set - letters_guessed_set)
# convert list of str to single str
return ''.join(available_letters)
This way you can do a simple subtraction to retrieve the list of available letters and then join this list to a single string.
No manual iteration needed
Note: if you want to preserve the sorted order of the letters still available, use Pythons sort function before returning the string
available_letters.sort()

how can I deal with the garbled string like '\xe7\xbe\x8e'?

I have a list of words like s = ['a','\xe7\xbe\x8e\xe7','b'], and I want to remove the members like '\xe7\xbe\x8e\xe7', but I cannot think of any useful method. I have never deal with such kind of encoded or decoded words. I wish any suggestion in python. Thanks!
def is_ascii(s):
return all(ord(c) < 128 for c in s)
s=[e for e in s if is_ascii(e)]
Try this. It will remove entries with non-ascii characters (like \xe7\xbe\x8e\xe7). Hope this helps!
You can check if each word in a list is alphanumeric using isalnum
function. If word is alphanumeric then keep it otherwise drop it. This can be achieved using list comprehension
>>> s = ['a','\xe7\xbe\x8e\xe7','b']
>>> [a for a in s if a.isalnum()]
>>> ['a', 'b']
Note: isalnum checks if string is alphanumeric i.e. contains letters and/or numbers. If you want to allow letters only then use isalpha instead
Try this:
import itertools
s = ['a','\xe7\xbe\x8e\xe7','b']
for i in range(s.count("\xe7\xbe\x8e\xe7")):
s.remove('\xe7\xbe\x8e\xe7')
Then all occurences of "\xe7\xbe\x8e\xe7" will be removed from the list.

mapping letters to pictures in Tkinter

I am writing a program in Tkinter (and I am also using PIL),python, that is "translating" entered words on croatian to "Glgoljica". glagoljica is an old croatian alphabet that looks like this:
So I was wondering if there is a way to solve this with the dictionaries in Tkinter? For example can I map a letter "a" "with a picture of letter "a" on "glagoljica" ,letter b with pictures of letter "b" on glagoljica,so that as and end-result user gets a statement that is fully translated on that old croatian alphabet?
What I want is algorithm bellow ,but just with pics (instead of strings) as a values of dict.keys().
dict={}
dict["a"]="e"
dict
>>>{'a': 'e'}
dict["i"]="u"
word="ai"
string=""
for letter in word:
if letter in dict:
string+=dict[letter]
>>> string
'eu'
The upper/lowercase glagoljica alphabet occupies unicode block U+2C00–U+2C5F, with U+2C2F and U+2C5F undefined. Tkinter can handle and, depending on your system and the font you use, display the characters. PIL should not be needed.
If you use a dict, it should map slavic chars to glagoljica chars.
glag = {'\u0410':'\u2C00', '\u0410':'\u2c01',} # etc
print('\u0410', glag['\u0410'])
# ('А', 'Ⰱ')
I am using 3.4.2 on Win7 with Lucida Console.
However, instead of an explicit loop, string translation should use str.translate and a table from str.maketrans.
trans1 = str.maketrans(glag)
print('ААБАБ'.translate(trans1))
#'ⰁⰁБⰁБ'
With this, a dict object is not needed.
trans2 = str.maketrans('АБ', 'ⰁБ') # could enter with \u excapes
print('ААБАБ'.translate(trans1))
#'ⰁⰁБⰁБ'

Python, breaking up Strings

I need to make a program in which the user inputs a word and I need to do something to each individual letter in that word. They cannot enter it one letter at a time just one word.
I.E. someone enters "test" how can I make my program know that it is a four letter word and how to break it up, like make my program make four variables each variable set to a different letter. It should also be able to work with bigger and smaller words.
Could I use a for statement? Something like For letter ste that letter to a variable, but what is it was like a 20 character letter how would the program get all the variable names and such?
Do you mean something like this?
>>> s = 'four'
>>> l = list(s)
>>> l
['f', 'o', 'u', 'r']
>>>
Addendum:
Even though that's (apparently) what you think you wanted, it's probably not necessary because it's possible for a string to hold virtually any size of a word -- so a single string variable likesabove should be good enough for your program verses trying to create a bunch of separately named variables for each character. For one thing, it would be difficult to write the rest of the program because you wouldn't to know what valid variable names to use.
The reason it's OK not to have separate variable for each character is because a single string can have any number of characters in it as well as be empty. Python's built-inlen()function will return a count of the number of letters in a string if applied to one, so the result oflen(s)in the above would be4.
Any character in a string can be randomly accessed by indexing it with an integer between0andlen(s)-1inside of square brackets, so to reference the third character you would uses[2]. It's useful to think of the index as the offset or the character from the beginning of the string.
Even so, in Python using indexing is often not needed because you can also iteratively process each character in a string in aforloop without using them as shown in this simple example:
num_vowels = 0
for ch in s:
if ch in 'aeiou':
num_vowels += 1
print 'there are', num_vowels, 'vowel(s) in the string', s
Python also has many other facilities and built-ins that further help when processing strings (and in fact could simplify the above example), which you'll eventually learn as you become more familiar with the language and its many libraries.
When you iterate a string, it returns the individual characters like
for c in thestring:
print(c)
You can use this to put the letters into a list if you really need to, which will retain its order but list(string) is a better choice for that (be aware that unordered types like dict or set do not guarantee any order).
You don't have to do any of those; In Python, you can access characters of a string using square brackets:
>>> word = "word"
>>> print(word[0])
w
>>> print(word[3])
d
>>> print(len(word))
4
You don't want to assign each letter to a separate variable. Then you'd be writing the rest of your program without even being able to know how many variables you have defined! That's an even worse problem than dealing with the whole string at once.
What you instead want to do is have just one variable holding the string, but you can refer to individual characters in it with indexing. Say the string is in s, then s[0] is the first character, s[1] is the second character, etc. And you can find out how far up the numbers go by checking len(s) - 1 (because the indexes start at 0, a length 1 string has maximum index 0, a length 2 string has maximum index 1, etc).
That's much more manageable than figuring out how to generate len(s) variable names, assign them all to a piece of the string, and then know which variables you need to reference.
Strings are immutable though, so you can't assign to s[1] to change the 2nd character. If you need to do that you can instead create a list with e.g. l = list(s). Then l[1] is the second character, and you can assign l[1] = something to change the element in the list. Then when you're done you can get a new string out with s_new = ''.join(l) (join builds a string by joining together a sequence of strings passed as its argument, using the string it was invoked on to the left as a separator between each of the elements in the sequence; in this case we're joining a list of single-character strings using the empty string as a separator, so we just get all the single-character strings joined into a single string).
x = 'test'
counter = 0
while counter < len(x):
print x[counter] # you can change this to do whatever you want to with x[counter]
counter += 1

Categories

Resources