UnicodeWarning: special characters in Tkinter - python

I have written a program in Tkinter (Python 2.7), a scrabblehelper in Norwegian which contains some special characters (æøå), which means my wordlist (ordliste) contains words with special characters.
When I run my function finnord(c*), it returns 'cd'. I am using an entry.get() to get the word to put in my function.
My problem is with the encoding of entry.get(). I have local coding UTF-8, but I get an UniCodeError when I am writing any special characters in my entrybox and matching them to my wordliste.
Here is my output.
Warning (from warnings module):
File "C:\pythonprog\scrabble\feud.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
When i write in my shell:
> ordinn.get()
u'k\xf8**e'
> ordinn.get().encode('utf-8')
'k\xc3\xb8**e'
> print ordinn.get()
kø**e
> print ordinn.get().encode('utf-8')
kø**e
Anyone knows why I can't match ordinn.get() (entry) to my wordlist ?

I can reproduce the error this way:
% 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.
>>> 'k\xf8**e' in [u'k\xf8**e']
__main__:1: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
False
So perhaps s is a str object, and liste or ordliste contains unicode, or (as eryksun points out in the comments) vice versa. The solution is to decode the str objects (most likely with the utf-8 codec) to make them unicode.
If that does not help, please print out and post the output of
print(repr(s))
print(repr(liste))
print(repr(ordliste))
I believe the problem can be avoided by converting all strings to unicode.
When you generate ordliste from norsk.txt, use
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]
Convert all user input to unicode as soon as possible:
def get_unicode(widget):
streng = widget.get()
try:
streng = streng.decode('utf-8')
except UnicodeEncodeError:
pass
return streng
So perhaps try this:
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()

Related

Custom encoding and decoding UTF special characters

Just for fun I've been embedding text in images. The following code is a distillation and demonstration of the encoding and decoding mechanism I am using.
class encChar:
def __init__(self,char):
self.p = self.enc(char)
def enc(self,char):
d = bin(ord(char)).split('b')[1]
while len(d)<8:
d = "0"+d
rdif = int(d[0])*4 + int(d[1])*2 + int(d[2])*1
gdif = int(d[3])*2 + int(d[4])*1
bdif = int(d[5])*4 + int(d[6])*2 + int(d[7])*1
return (rdif,gdif,bdif)
def dec(self):
dmap = {0:"000",1:"001",2:"010",3:"011",4:"100",5:"101",6:"110",7:"111"}
r = dmap[self.p[0]]
g = dmap[self.p[1]][1:]
b = dmap[self.p[2]]
n = int(r+g+b,2)
return chr(int(r+g+b,2))
testStr = """Languages
Deutsch
Español
Français
한국어
Italiano
Русский
Tagalog
Tiếng Việt
中文"""
result= ""
for line in testStr.split("\n"):
result+=line+"\n"
print(line)
print("".join([encChar(k).dec() for k in line]))
result+="".join([encChar(k).dec() for k in line])+"\n"
print()
result+="\n"
with open("errorop.txt","w",encoding="utf8") as op:
op.write(result)
Which produces the following document:
Languages
Languages
Deutsch
Deutsch
Español
Español
Français
Français
한국어
Õ­Å
Italiano
Italiano
Русский
Tagalog
Tagalog
Tiếng Việt
Tiõng Viöt
中文
Ë
As you can see several runes are altered by the process and I'm wondering how I can preserve them through this process.

OEM non printable characters in Python strings

I´m trying to port some Delphi code that sends data to a Universe database. In order to make the text legible by the DB we need to encode it in OEM.
In Delphi is done this way:
procedure TForm1.GenerarTablasNLS;
var
i: integer;
begin
for i := 0 to 255 do
begin
TablaUV_NLS[i] := AnsiChar(i);
TablaNLS_UV[i] := AnsiChar(i);
end;
// Nulo final
TablaUV_NLS[256] := #0;
TablaNLS_UV[256] := #0;
OemToCharA(#TablaUV_NLS[1], #TablaUV_NLS[1]);
CharToOemA(#TablaNLS_UV[1], #TablaNLS_UV[1]);
And then we translate our text simply like this
function StringToUniverse(const Value: string): AnsiString;
var
p: PChar;
q: PAnsiChar;
begin
SetLength(Result, Length(Value));
if Value = '' then Exit;
p := Pointer(Value);
q := Pointer(Result);
while p^ <> #0 do
begin
q^ := TablaNLS_UV[Ord(AnsiChar(p^))];
Inc(p);
Inc(q);
end;
end;
I follow the same logic in Python using a dictionary that stores each character translation
class StringUniverseDict(dict):
def __missing__(self, key):
return key
TablaString2UV = StringUniverseDict()
def rellenar_tablas_codificacion():
TablaString2UV['á'] = ' ' # chr(225) = chr(160)
TablaString2UV['é'] = '‚' # chr(233) = chr(130)
TablaString2UV['í'] = '¡' # chr(237) = chr(161)
TablaString2UV['ó'] = '¢' # chr(243) = chr(162)
TablaString2UV['ú'] = '£' # chr(250) = chr(163)
TablaString2UV['ñ'] = '¤' # chr(241) = chr(164)
TablaString2UV['ç'] = '‡' # chr(231) = chr(135)
TablaString2UV['Á'] = 'µ' # chr(193) = chr(181)
TablaString2UV['É'] = chr(144) # chr(201) = chr(144)
TablaString2UV['Í'] = 'Ö' # chr(205) = chr(214)
TablaString2UV['Ó'] = 'à' # chr(211) = chr(224)
TablaString2UV['Ñ'] = '¥' # chr(209) = chr(165)
TablaString2UV['Ç'] = '€' # chr(199) = chr(128)
TablaString2UV['ü'] = chr(129) # chr(252) = chr(129)
TablaString2UV[chr(129)] = '_' # chr(129) = chr(095)
TablaString2UV[chr(141)] = '_' # chr(141) = chr(095)
TablaString2UV['•'] = chr(007) # chr(149) = chr(007)
TablaString2UV['Å'] = chr(143) # chr(197) = chr(143)
TablaString2UV['Ø'] = chr(157) # chr(216) = chr(157)
TablaString2UV['ì'] = chr(141) # chr(236) = chr(141)
This works "fine" as long as I translate using printable characters. For example, the string
"á é í ó ú ñ ç Á Í Ó Ú Ñ Ç"
is translated, in Delphi, to the following bytes:
0xa0 0x20 0x82 0x20 0xa1 0x20 0xa2 0x20 0xa3 0x20 0xa4 0x20 0x87 0x20 0xb5 0x20 0xd6 0x20 0xe0 0x20 0xe9 0x20 0xa5 0x20 0x80 0xfe 0x73 0x64 0x73
(á translates to ' ', which is chr(160) or 0xA0 in hexa. é is '‚' or chr(130), 0x82 in hexa, í is '¡', char(161) or 0xA1 in hexa and so on)
In Python, when I try to encode this to OEM I do the following:
def convertir_string_a_universe(cadena_python):
resultado = ''
for letra in cadena_python:
resultado += TablaString2UV[letra]
return resultado
And then, to get the bytes
txt_registro = convertir_string_a_universe(txt_orig)
datos = bytes(txt_registro, 'cp1252')
With this I get the following bytes:
b'\xa0 \x82 \xa1 \xa2 \xa3 \xa4 \x87 \xb5 \xd6 \xe0 \xe9 \xa5 \x80 \x9a'
My problem is that this OEM encoding uses non-printable characters, like in 'É' = chr(144) (0x90 in hexa). If I try to call bytes(txt_registro, 'cp1252') with an array where I hava translated 'É' into chr(0x90) I get this error:
caracteres_mal = 'Éü'
txt_registro = convertir_string_a_universe(txt_orig)
datos = bytes(txt_registro, 'cp1252')
File "C:\Users\Hector\PyCharmProjects\pyuniverse\pyuniverse\UniverseRegister.py", line 138, in reconstruir_registro_universe
datos = bytes(txt_registro, 'cp1252')
File "C:\Users\Hector\AppData\Local\Programs\Python\Python36-32\lib\encodings\cp1252.py", line 12, in encode
return codecs.charmap_encode(input,errors,encoding_table)
UnicodeEncodeError: 'charmap' codec can't encode character '\x90' in position 0: character maps to <undefined>
How can I do this OEM encoding without raising this UnicodeEncodeError?
This is because cp1252 does not know about chr(0x90). If you try with utf-8 instead, it will work.
>>> chr(0x90).encode("utf8")
b'\xc2\x90'
I don't understand why you are trying to convert to cp1252 though: you have applied a custom conversion map and then, with bytes(txt_registro, 'cp1252'), you are converting your result again to cp1552.
I think what you are looking for is something like:
datos = bytes(txt_orig, 'uv')
where uv is your cutom codec.
So you would have to write an encoder and a decoder for it (which is basically what you have done already). Take a look at https://docs.python.org/3/library/codecs.html#codecs.register
to register a new codec. The function you will register with it should return a CodecInfo object described upper in the documentation.
import codecs
def buscar_a_uv(codec):
if codec == "uv":
return codecs.CodecInfo(
convertir_string_a_universe, convertir_universe_a_string, name="uv")
else:
return None
codecs.register(buscar_a_uv)
datos = bytes(txt_orig, 'uv')
EDIT
The encoder/decoder functions should return bytes, so you would need to update convertir_string_a_universe a bit.

When using win32print + cx_Freeze, print instruction doesn't work without producing any error

Windows 10 (x64)
Python 3.6.3
cx_Freeze 5.1.1
pypiwin32 223 / pywin32 224
I made a module for printing, the module works fine when launching it as a script.
Once passed through cx_Freeze, the print command doesn't work without producing any error message.
Here is my setup.py for creating builds (by: python setup.py build)
# -*- coding: utf-8 -*-
import sys,os
from cx_Freeze import setup, Executable
PythonPath = os.path.split(sys.executable)[0] #get python path
includes = []
excludes = []
packages = ["win32print"]
includefiles = ["OptiWeb.ico"]
options = {"includes": includes,
"excludes": excludes,
"packages": packages,
"include_files": includefiles,
"optimize":2
}
base=None
if sys.platform == 'win32':
base = "Win32GUI"
options["include_msvcr"] = True
executables = [Executable(script="OptiPrint.py",base=base,icon="Optiweb.ico")]
setup(name = "OptiPrint",options = {"build_exe": options},version = "1.0",author = "ND",description = "print test",executables = executables)
And now my code for printing:
# coding: utf8
import win32print
class ZPLLabel(object):
def __init__(self, printerName):
self.printerName = printerName
self.printerDevice = win32print.OpenPrinter(self.printerName)
self.job = win32print.StartDocPrinter(self.printerDevice, 1, ("Etiquette", None, "RAW"))
self.eraseAll()
self.defineFormat()
def eraseAll(self):
win32print.StartPagePrinter(self.printerDevice)
str2print="~JA"
win32print.WritePrinter(self.printerDevice, str2print.encode("utf8")) #écrit le format d'étiquette
win32print.EndPagePrinter(self.printerDevice) # indique la fin de ce qu'il y a à imprimer
self.printerDevice.close() # ferme le canal d'impression et déclenche l'impression de ce qui précède
#del self.job
self.printerDevice=win32print.OpenPrinter(self.printerName)
self.job = win32print.StartDocPrinter(self.printerDevice, 1, ("Etiquette", None, "RAW"))
def defineFormat(self):
margeLeft = 150
margeTop = 20
interLine = 39
shiftLeft = 20
vDec = 25
#win32print.StartPagePrinter(p)
str2print="^XA\n" #debut de format
str2print+="^CI28"
#FO origine du champ, 100 pos x du champ en dots, 50 pos y du champ en dots
# l'imprimantes est 200 dpi (dotsper inch = 7.874 dots par mm, ici 12.7mm, 6.35mm)
#ADN : A ==> font, D==> font D, N ==> Orientation Normale, 36 hauteur caractère en dots, 20 Largeur caractère en dots
#FD données à imprimer pour le champ
#FS fin du champ
str2print+="^DFFORMAT"
str2print+="^LH"+str(margeLeft)+","+str(margeTop)
#un cadre arrondi
str2print+="^FO0,0^GB500,330,3,B,2^FS"
#str2print+="^FO"+str(shiftLeft)+","+str(interLine)+"^ADN,24,12^FDEtiquette de débit Sangle^FS\n" #format de l'étiquette
str2print+="^FO"+str(shiftLeft)+","+str(1*interLine-vDec) +"^ADN,32,14^FDOF N° : ^FS^FO"+str(shiftLeft+160)+","+str(1*interLine-vDec) +"^ADN,32,14^FN1^FS"
str2print+="^FO"+str(shiftLeft)+","+str(2*interLine-vDec) +"^ADN,32,14^FDPRODUIT : ^FS^FO"+str(shiftLeft+215)+","+str(2*interLine-vDec) +"^ADN,32,14^FN2^FS"
str2print+="^FO"+str(shiftLeft)+","+str(3*interLine-vDec) +"^ADN,24,12^FN3^FS"
str2print+="^FO"+str(shiftLeft)+","+str(4*interLine-vDec) +"^ADN,32,14^FDSANGLE : ^FS^FO"+str(shiftLeft+200)+","+str(4*interLine-vDec) +"^ADN,32,14^FN4^FS"
str2print+="^FO"+str(shiftLeft)+","+str(5*interLine-vDec) +"^ADN,24,12^FN5^FS"
str2print+="^FO"+str(shiftLeft)+","+str(6*interLine-vDec) +"^ADN,28,13^FDNombre de coupe : ^FS^FO"+str(shiftLeft+250)+","+str(6*interLine-vDec) +"^ADN,28,13^FN6^FS"
str2print+="^FO"+str(shiftLeft)+","+str(7*interLine-vDec) +"^ADN,28,13^FDLongueur coupée : ^FS^FO"+str(shiftLeft+250)+","+str(7*interLine-vDec) +"^ADN,28,13^FN7^FS"
str2print+="^FO"+str(shiftLeft)+","+str(8*interLine-vDec) +"^ADN,24,12^FDEmplacement : ^FS^FO"+str(shiftLeft+160)+","+str(8*interLine-vDec) +"^ADN,24,12^FN8^FS"
str2print+="^XZ" # fin du format d'étiquette
win32print.WritePrinter(self.printerDevice, str2print.encode("utf8")) #écrit le format d'étiquette
def printLabel(self, orderNum, productSku, productName, webSku, webName, partNum, partLength, emplacement):
str2print="^XA\n" #debut étiquette
str2print+="^XFFORMAT" #rappel du format enregistré
str2print+="^FN1^FD"+orderNum+"^FS"
str2print+="^FN2^FD"+productSku+"^FS"
str2print+="^FN3^FD"+productName+"^FS"
str2print+="^FN4^FD"+webSku+"^FS"
str2print+="^FN5^FD"+webName+"^FS"
str2print+="^FN6^FD"+str(partNum)+"^FS"
str2print+="^FN7^FD"+partLength+"^FS"
str2print+="^FN8^FD"+emplacement+"^FS"
str2print+="^XZ" # fin du format d'étiquette
win32print.WritePrinter(self.printerDevice, str2print.encode("utf8")) #écrit l'étiquette
def endLabel(self):
self.printerDevice.close() # ferme le canal d'impression et déclenche l'impression de ce qui précède
del self.job
def newPrintLabel():
zpl = ZPLLabel('Zebra ZP 450 CTP')
zpl.printLabel("20009999", "1035691", "Harnais Energy TWIN ss porte outil L/XL",
"90008318", "SA/SANGLE NOIRE 20 MM", 35, "0.38m", "Bavaroise réglable")
zpl.endLabel()
if __name__ == '__main__':
app = newPrintLabel()
I suppose, some package or dll is missing to make it run when frozen.
I tried to add win32api, win32com but it doesn't change the result.
Thanks for your help which is for sure welcome.
Try to use win32ui and win32con as done in the answers of python win32print not printing.
In this case you should also keep base defined as in your original question (regarding my comment to your question).
For those who experiment a such issue.
My code was not properly written:
To each StartDocPrinter instruction must correspond a EndDocPrinter instruction, apparently this not cause trouble with script but has impact on frozen version.
So the correct thread of instructions must be something like:
self.printerName = printerName
self.printerDevice = win32print.OpenPrinter(self.printerName)
self.job = win32print.StartDocPrinter(self.printerDevice, 1, ("Etiquette", None, "RAW"))
win32print.StartPagePrinter(self.printerDevice)
str2print="..." # define what you want to print
win32print.WritePrinter(self.printerDevice, str2print.encode("utf8")) #write
win32print.EndPagePrinter(self.printerDevice) # end the page
win32print.EndDocPrinter(self.printerDevice) # end the doc
self.printerDevice.close() # close the printer thread

Problem with writing to file second time, Python3

I have created a phonebook with tkinker using Python 3.6
When I add persons to phonebook it save it to a file.
When I load the program again it loads the file as it should.
If I add 2 person at first run, all works fine.
Second run, I add one person and it adds an empty line at index 1 and adds the person below as it should.
Third run, I add one person, it adds a new line at index 1 and a person last in the list.
Now I get 2 empty lines.
I can't figure out why it creates an empty space at index 1 . It should not do it.
Here is the code, comments are in Swedish so sorry about it.
How I write to the file is in function lägg_till()
It will auto create kontakter.txt when you run it first time.
"Lägg till" means add in Sweden and "Avsluta" is quit the program.
from tkinter import *
import os.path
root = Tk()
root.geometry("640x640+200+100")
root.title("Telefon listan")
def avsluta():
quit()
def spara():
#Spara kontakter till fil.
name = entry_1.get()
mobil = entry_2.get()
if name == "" or mobil == "" :
pass
else:
with open("kontakter.txt","w") as file:
file.write("\n".join(kontakter.get(0,END)))
def ta_bort():
# Ta bort kontakter,genom att välja index av element och sparar värdet i variabel index.
index = kontakter.curselection()
print(index)
kontakter.delete(index)
def lägg_till():
# Ta inmatade värden från name,mobil och spara i kontakter.
# Använder .get() för att hämta
name = entry_1.get()
mobil = entry_2.get().replace(" ", "") # Använder replace för att rensa whitespace
# Varning när alla värden inte är ifyllda
if name == "" or mobil == "" :
label_error.config(text="Alla fälten är inte ifyllda")
else:
# trycka in dessa i kontakter med .insert() END för slutet av listan, dvs index "kan vara 0,1,2,3"
#Rensar error fältet innan man lägger till kontakten
label_error.config(text="")
kontakter.insert(END,name + " - " + mobil)
# Rensa fältet efter lägg till
entry_1.delete(0,END)
entry_2.delete(0,END)
kontakt = kontakter.get(0,END)
with open("kontakter.txt","w") as file:
file.write("\n".join(kontakt))
def uppdatera():
# Hämta det markerade data
index = kontakter.curselection()
name = entry_1.get()
mobil = entry_2.get()
# Varning när alla värden inte är ifyllda
if name == "" or mobil == "" :
label_error.config(text="Alla fälten är inte ifyllda")
else:
# trycka in dessa i kontakter med .insert() END för slutet av listan, dvs index "kan vara 0,1,2,3"
#Rensar error fältet innan man lägger till kontakten
label_error.config(text="")
# Raderar det ifyllda data
kontakter.delete(index)
#Skriver nytt
kontakter.insert(index,name + "-" + mobil)
entry_1.delete(0,END)
entry_2.delete(0,END)
# Skapar frame
#Namn
fram_1 = Frame(root)
fram_1.pack()
#Mobil
fram_2 = Frame(root)
fram_2.pack()
#Knappar
fram_3 = Frame(root)
fram_3.pack()
# Listbox
fram_4 = Frame(root)
fram_4.pack()
#Skapar label
#Namn
label_1 = Label(fram_1,text="Name:")
label_1.grid(row=0, column=0)
#Mobil
label_2 = Label(fram_2,text="Mobil:")
label_2.grid(row=1,column=0)
# Skapar entry
#namn
entry_1 = Entry(fram_1)
entry_1.grid(row=0,column=1)
#Mobil
entry_2 = Entry(fram_2)
entry_2.grid(row=1,column=2,)
# Kolla om filen finns, annars skapa den, behöver importera os.path
if not os.path.exists("kontakter.txt"):
open('kontakter.txt', 'w').close()
else:
pass
# Läsa från fil
data = []
with open("kontakter.txt" ,"r") as fil:
for line in fil:
data += [line]
# Listbox
kontakter = Listbox(fram_4,height=8,width=40,bg="pink")
kontakter.grid(row=0,column=0)
# Lägger till kontakter , första värdet är index följt av värde,
kontakter.insert(END,)
#Läsa in från fil
for i in range(len(data)):
kontakter.insert(i+0 , data[i])
# Error
label_error = Label(root,text="",fg="red")
label_error.pack()
# Knappar
# knapp Lägg till
button_1 = Button(fram_3,text="Lägg till",command=lägg_till)
button_1.grid(row=0,column=0)
# knapp edit
button_2 = Button(fram_3,text="Uppdatera",command=uppdatera)
button_2.grid(row=0,column=1)
# Knapp delete
button_3 = Button(fram_3,text="Radera",command=ta_bort)
button_3.grid(row=0,column=2)
# Knapp avsluta
button_4 = Button(fram_3,text="Avsluta",command=avsluta)
button_4.grid(row=0,column=3)
button_5 = Button(fram_3,text="Spara",command=spara)
button_5.grid(row=0,column=4)
root.attributes("-topmost", True)
root.mainloop()
Inside lägg_till() when you open the file use ab instead of w:
with open("kontakter.txt","ab") as file:
file.write("\n".join(kontakt))
By adding .strip() , I made workaround, but I think problem is still there.
# Läsa från fil
data = []
with open("kontakter.txt" ,"r") as fil:
for line in fil.readlines():
data += [line.strip()] #.strip() fix the problem
fil.close()
The problem in your program is kontakt = kontakter.get(0,END), which returns your data as follows :
('1 - 1\n', '2 - 2', '3 - 3')
Note that the third entry (3 - 3) is made after the GUI was closed once. By joining together with '\n'.join(), you get an additional space character:
'1 - 1\n\n2 - 2\n3 - 3\n'
I don't know the exact reason why this only happens if you close the program once.
You can avoid this conflict by using 'a' instead of 'w', which simply appends the string in the text file.
with open("kontakter.txt","a") as file:
file.write(name + " - " + mobil + '\n')

How to convert string to seo-url?

I would like to convert a accented string to a seo-url ...
For instance:
"Le bébé (de 4 ans) a également un étrange "rire"" to :
"le-bebe-de-4-ans-a-egalement-un-etrange-rire"
Any solution, please ?
Thanks !
This is what I use:
def _doStringSEOptiomization(objectName,pageName,lang,objectId):
"""
Prende in input il nome di un'offerta e svolge dei passi:
1- Trasforma tutte le variazioni delle vocali
in vocali normali
2- Attraverso una serie di REGEX, elimina i caratteri non desiderati e torna
una stringa da inserire in un link adatto ai motori di ricerca e alle indicizzazioni
"""
try:
import re #importo il modulo per le REGEX
Speaker.log_debug(GREEN("core.ws_site.do_sites_offers_data_redux._doStringSEOptiomization() input: objectName=%s, pageName=%s, lang=%s, objectId=%s" % (objectName,pageName,lang,objectId)))
#mappa dei caratteri html-entity e unicode
vocalMap = { 'a' : ['à','á','â','ã','ä','å','æ','à','á','â','ã','ä','å','ā','æ'],
'e' : ['è','é','ê','ë','è','é','ê','ë','ē'],
'i' : ['ì','í','î','ï','ì','í','î','ï','ī'],
'o' : ['ò','ó','ô','œ','õ','ö','ò','ó','ô','œ','õ','ö','ō'],
'u' : ['ù','ú','û','ü','ù','ú','û','ü','ū']
}
objectName = objectName.lower() #trasformo la stringa di partenza in caratteri minuscoli
for vocale, lista in vocalMap.iteritems(): #per ogni elemento della mappa avrà una chiave ed una lista
for elemento in lista: #itero su tutti gli elementi della lista
objectName = objectName.replace(elemento,vocale) #sostituisco nel nome dell'offerta, la vocale all' HTML-entity
objectName = objectName.replace("/","-")
objectName = re.sub("[^a-z0-9_\s-]","",objectName) #######################################
objectName = re.sub("[\s-]+"," ",objectName) #strippo tutti i caratteri non voluti:#
objectName = re.sub("[\s_]","-",objectName) #######################################
objectName = pageName+"--"+objectName
objectName += "-"+lang+"-"+str(objectId) #aggiungo la lingua e l'id dell'offerta
except Exception,s:
Speaker.log_error("_doStringSEOptiomization(): Error=%s"%RED(s))
return objectName
You have to adapt it for your situation.
This might (or might not) be enough:
import re
import unidecode
def normalized_id(title):
title = unidecode.unidecode(title).lower()
return re.sub('\W+', '-', title.replace("'", '')).strip('-')
>>> a = u'Le bébé (de 4 ans) a également un étrange "rire"'
>>> r = unicodedata.normalize('NFKD',a).encode('cp1256','ignore')
>>> r = unicode(re.sub('[^\w\s-]','',r).strip().lower())
>>> r = re.sub('[-\s]+','-',r)
>>> print r
le-bebe-de-4-ans-a-egalement-un-etrange-rire
I use cp1256 (latin 1) to handle accented characters...
Perfect ! Thanks a lot !
If you have Django around, you can use its defaultfilter slugify (or adapt it for your needs).
[~]$ python
Python 2.7.1 (r271:86882M, Nov 30 2010, 10:35:34)
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import unicodedata
>>> import re
>>> def seo_string(x):
... r = unicodedata.normalize('NFKD',x).encode('ascii','ignore')
... r = unicode(re.sub('[^\w\s-]','',x).strip().lower())
... return re.sub('[-\s]+','-',r)
...
>>> seo_string(u'Le bébé (de 4 ans) a également un étrange "rire"')
u'le-bb-de-4-ans-a-galement-un-trange-rire'
With thanks to the great slugify of django's built-in filters, however it won't do replacement of é with e like the solution posted by #doncallisto
Here are the several ways to do so: Generating Slugs By Armin Ronacher.

Categories