#python #encoding #tkinter #character
#питон #кодирование #tkinter #характер #python #символ
Вопрос:
Я написал программу на Tkinter (Python 2.7), scrabblehelper на норвежском языке, которая содержит некоторые специальные символы ( æøå
), что означает, что мой список слов (ordliste) содержит слова со специальными символами.
Когда я запускаю свою функцию finnord(c*), она возвращает ‘cd’. Я использую entry.get()
, чтобы получить слово для вставки в мою функцию.
Моя проблема связана с кодировкой entry.get(). У меня есть локальное кодирование UTF-8
, но я получаю сообщение UniCodeError
, когда я пишу какие-либо специальные символы в своем поле ввода и сопоставляю их со своим списком слов.
Вот мой вывод.
Warning (from warnings module):
File "C:pythonprogscrabblefeud.py", line 46
if s not in liste and s in ordliste:
UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode -
interpreting them as being unequal
Когда я пишу в своей оболочке:
> ordinn.get()
u'kxf8**e'
> ordinn.get().encode('utf-8')
'kxc3xb8**e'
> print ordinn.get()
kø**e
> print ordinn.get().encode('utf-8')
kø**e
Кто-нибудь знает, почему я не могу сопоставить ordinn.get() (запись) с моим списком слов?
Ответ №1:
Я могу воспроизвести ошибку таким образом:
% python
Python 2.7.2 (default, Oct 4 2011, 20:03:08)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'kxf8**e' in [u'kxf8**e']
__main__:1: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
False
Так что, возможно, s
это str object
и liste
или ordliste
содержит unicode
, или (как указывает эриксун в комментариях) наоборот. Решение состоит в том, чтобы декодировать str object
s (скорее всего, с помощью utf-8
кодека), чтобы создать их unicode
.
Если это не поможет, пожалуйста, распечатайте и опубликуйте вывод
print(repr(s))
print(repr(liste))
print(repr(ordliste))
Я считаю, что проблемы можно избежать, преобразовав все строки в unicode
.
-
При создании
ordliste
изnorsk.txt
используйтеcodecs.open('norsk.txt','r','utf-8')
:encoding = sys.stdin.encoding with codecs.open('norsk.txt','r','utf-8') as fil: ordliste = [line.rstrip(u'n') for line in fil]
-
Преобразуйте весь пользовательский ввод в unicode как можно скорее:
def get_unicode(widget): streng = widget.get() try: streng = streng.decode('utf-8') except UnicodeEncodeError: pass return streng
Так что, возможно, попробуйте это:
import Tkinter as tk
import tkMessageBox
import codecs
import itertools
import sys
alfabetet = (u"abcdefghijklmnopqrstuvwxyz"
u"N{LATIN SMALL LETTER AE}"
u"N{LATIN SMALL LETTER O WITH STROKE}"
u"N{LATIN SMALL LETTER A WITH RING ABOVE}")
encoding = sys.stdin.encoding
with codecs.open('norsk.txt','r',encoding) as fil:
ordliste = set(line.rstrip(u'n') for line in fil)
def get_unicode(widget):
streng = widget.get()
if isinstance(streng,str):
streng = streng.decode('latin-1')
return streng
def siord():
alfa=lagtabell()
try:
streng = get_unicode(ordinn)
ordene=finnord(streng,alfa)
if len(ordene) == 0:
# There are no words that match
tkMessageBox.showinfo('Dessverre..','Det er ingen ord som passer...')
else:
# Done: The words that fit the pattern
tkMessageBox.showinfo('Ferdig',
'Ordene som passer er:n' ordene.encode('utf-8'))
except Exception as err:
# There has been a mistake .. Check your word
print(repr(err))
tkMessageBox.showerror('ERROR','Det har skjedd en feil.. Sjekk ordet ditt.')
def finnord(streng,alfa):
liste = set()
for substitution in itertools.permutations(alfa,streng.count(u'*')):
s = streng
for ch in substitution:
s = s.replace(u'*',ch,1)
if s in ordliste:
liste.add(s)
liste = [streng] list(liste)
return u','.join(liste) u'.'
def lagtabell():
tinbox = get_unicode(bokstinn)
if not tinbox.isalpha():
alfa = alfabetet
else:
alfa = tinbox.lower()
return alfa
root = tk.Tk()
root.title('FeudHjelper av Martin Skow Røed')
root.geometry('400x250 450 200')
# root.iconbitmap('data/ikon.ico')
skrift1 = tk.Label(root,
text = '''
Velkommen til FeudHjelper. Skriv inn de bokstavene du har, og erstatt ukjente med *.
F. eks: sl**ge
Det er kun lov til å bruke tre stjerner, altså tre ukjente bokstaver.''',
font = ('Verdana',8), wraplength=350)
skrift1.pack(pady = 5)
ordinn = tk.StringVar(None)
tekstboks = tk.Entry(root, textvariable = ordinn)
tekstboks.pack(pady = 5)
# What letters do you have? Eg "ahneki". Leave blank here if you want all the words.
skrift2 = tk.Label(root, text = '''Hvilke bokstaver har du? F. eks "ahneki". La det være blankt her hvis du vil ha alle ordene.''',
font = ('Verdana',8), wraplength=350)
skrift2.pack(pady = 10)
bokstinn = tk.StringVar(None)
tekstboks2 = tk.Entry(root, textvariable = bokstinn)
tekstboks2.pack()
knapp = tk.Button(text = 'Finn ord!', command = siord)
knapp.pack(pady = 10)
root.mainloop()
Комментарии:
1. Или списки слов имеют формат UTF-8 (
'kxc3xb8**e'
), а s изEntry.get()
— это Unicode, который не был закодирован. Это приводит к той же ошибке.2.repr(%), s, liste и ordliste возвращают то же значение, что и их оригинал. ссылка выделенная, — это мой скрипт. Я могу’
3. @eryksun: Спасибо за комментарий. Я думаю,
try..except
это безопаснее, чем использоватьisinstance
здесь. Я недостаточно умен, чтобы учитывать все возможные сбои в декодировании. 🙂 Меня смущает ваш комментарий «Декодирование юникода… может возникнуть ошибка UnicodeDecodeError, если кодировка по умолчанию не ‘ascii’ и отличается от sys.stdin.encoding». Здесь мы имеем дело с Python2, и кодировкой по умолчанию всегда является ‘ascii’ в Python2. Итак, как вы генерируете ошибку UnicodeDecodeError?4. @eryksun: Спасибо за помощь. Может ли ASCII,
str
возвращаемыйStringVar.get
, всегда быть правильно декодирован с помощьюlatin-1
независимо от значенияsys.stdin.encoding
?5. @eryksun: Если пользователь введет
€
(закодированный в cp1252) в запись Tkinter, успешно ли Tkinter / TCL преобразует ее в unicode или он вслепую попытается декодировать ее с помощью utf-8? Код, на который вы ссылаетесь, похоже, говорит, что он будет пытаться вслепуюutf-8
. Будет ли тогда сбой и возвратPyString_FromStringAndSize(s, len)
? Я не смог отследить определение этой функции. По-прежнему ли гарантируется возврат строки ASCII? Как это может быть, когда€
содержит старший бит?