mapping letters to pictures in Tkinter - python

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))
#'ⰁⰁБⰁБ'

Related

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 to make casefold() work on certain Arabic unicodes

I've got some issues with detecting the "equality" in Python 2.7 of some Arabic pairs of words:
أكثر vs اكثر
قائمة vs قائمه
إنشاء vs انشاء
The elements of each pair are not really identical, but they are written with different cases. An useful analogy for me (I don't know any Arabic) is Word vs word. They are not identical, but if I lowercase both of them, I'll obtain word vs word, which are identical. That's what I want to obtain from these 3 pairs of Arabic words.
I'm going to exemplify what I tried by now using the first pair (1. أكثر vs اكثر). By the way, the meaning of both Arabic words from the first pair is "menu" "more", but they have different cases (as a parallel: Menu vs menu More vs more). I don't know Arabic at all nor Arabic rules, so if someone who knows Arabic can confirm that those words are "identical" it would be great.
str1 = u'أكثر'
str2 = u'اكثر'
So what I'm trying to do is to bring str1 and str2 to the same form (if possible), so I want a function which produce the same output for both strings:
transform(str1) == transform(str2)
In English this can be achieved easily:
a = u'More'
b = u'more'
def transform(text):
return text.lower()
>>> transform(a) == transform(b)
>>> True
But, of course, this doesn't work for Arabic as there are no such things like lower case or upper case.
>>> str1
u'\u0623\u0643\u062b\u0631'
>>> str2
u'\u0627\u0643\u062b\u0631'
Note that only the first character differs in the unicode representation.
I also normalized the strings using:
import unicodedata
>>> n_str1 = unicodedata.normalize('NFKD', str1)
>>> n_str2 = unicodedata.normalize('NFKD', str2)
>>> n_str1
u'\u0627\u0654\u0643\u062b\u0631'
>>> n_str2
u'\u0627\u0643\u062b\u0631'
As you already noticed:
>>> n_str1 == n_str2
False
After that, I tried to use unicode.casefold() but it isn't available in Python 2. I've installed py2casefold library but it I didn't manage to obtain the equality between the strings. So I tried to use Python 3's unicode.casefold() but without any luck:
>>> str1.casefold() == str2.casefold()
False
>>> n_str1.casefold() == n_str2.casefold()
False
A solution for this in Python 2 would be perfect, but it would be great in Python 3 too.
Thank you.
These words are not identical: u'أكثر' and u'اكثر' are not the same. The first letter in the first word has the letter Alif with Hamazah on top of it, perhaps you couldn't notice that due to the small size of the glyph:
The first letter in the second word, however, is Alif *(from right-to-left):
And hence they don't compare equal. Each of these letters is represented by its own Unicode character code point. They don't compare equal from the perspective of the language too:
>>> u'أكثر'; u'اكثر'
u'\u0623\u0643\u062b\u0631'
u'\u0627\u0643\u062b\u0631'
They are not identical, but if I lowercase both of them, I'll obtain word vs word, which are identical. That's what I want to obtain from these 3 pairs of Arabic words.
There's no lower or upper case in Arabic. The words that you have in your hands are not the same, they have different letters. Some of the words have correct spelling while others have incorrect spelling. They may seem to be the same, but for Arabic readers they also may consider them to be the same, for language freaks, they're not the same. But they convey the meaning, your list of Arabic words in English roughly looks like this:
1- more, moore
2- menu, manu
3- establish, estblish
I'm going to exemplify what I tried by now using the first pair (1. أكثر vs اكثر). By the way, the meaning of both Arabic words from the first pair is "menu", but they have different cases (as a parallel: Menu vs menu)
No, أكثر means more. Your second pair means menu, but there's no such thing as Menu or menu in Arabic. I couldn't delve into details, because this would be off topic.

How could we get unicode from glyph id in python?

If I have glyph ids like below how can I get the unicode from them, the language is python that I am working on ? Also what I understand the second value is the glyph id but what do we call the first value and the third value?
(582, 'uni0246', 'LATIN CAPITAL LETTER E WITH STROKE'), (583, 'uni0247', 'LATIN SMALL LETTER E WITH STROKE'), (584, 'uni0248', 'LATIN CAPITAL LETTER J WITHSTROKE'), (585, 'uni0249', 'LATIN SMALL LETTER J WITH STROKE')
Kindly reply.
Actually I am trying to get the unicode from a given ttf file in python.Here is the code :
from fontTools.ttLib import TTFont
from fontTools.unicode import Unicode
from ttfquery import ttfgroups
from fontTools.ttLib.tables import _c_m_a_p
from itertools import chain
ttfgroups.buildTable()
ttf = TTFont(sys.argv[1], 0, verbose=0, allowVID=0,
ignoreDecompileErrors=True,
fontNumber=-1)
chars = chain.from_iterable([y + (Unicode[y[0]],) for y in x.cmap.items()] for x in ttf["cmap"].tables)
print(list(chars))`
This code I got from stackoverflow only but this gives the above output and not what I require. So could anybody please tell me how to fetch the unicodes from the ttf file or is it fine to convert the glyphid to unicode, will it yield to actual unicode ?
You can use the first field: unichr(x[0]), or equivalently the second field. Then you remove the "uni" part ([3:]) and you convert it to a hexadecimal valu'Ɇ'e, then to a character. Of course, the first method is faster and simpler.
unichr(int(x[1][3:], 16)) #for the first item you've showed, returns 'Ɇ', for the second 'ɇ'
If you use python3, chr instead of unichr.
Here is a simple way to find all unicode character in ttf file.
chars = []
with TTFont('/path/to/ttf', 0, ignoreDecompileErrors=True) as ttf:
for x in ttf["cmap"].tables:
for (code, _) in x.cmap.items():
chars.append(chr(code))
# now chars is a list of \uxxxx characters
print(chars)

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

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

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.

Categories

Resources