Nieuws:

Welkom, Gast. Alsjeblieft inloggen of registreren.
Heb je de activerings-mail niet ontvangen?

Auteur Topic: (opgelost) PyQt cross-platform textcoderingen (UTF-8)  (gelezen 5024 keer)

(opgelost) PyQt cross-platform textcoderingen (UTF-8)
« Gepost op: 2011/09/01, 14:20:57 »
Goedendag,

Het volgende probleem, op Linux wordt een euro-teken juist weergeven, op Windows wordt het teken niet herkend.
Nu heb ik diverse dingen geprobeerd met QString.fromUtf8() en unicode().

Na veel testen ben ik op het volgende resultaat gekomen:
self.ui.set_ppu.setPrefix(unicode(QString().fromUtf8("€")))Daar wordt het teken zowel op ubuntu als op windows (7) correct weergeven.

Echter de volgende code werkt niet:
price = locale.currency(formatCurrency(price))
item.setText(9, unicode(QString.fromUtf8(price)))
Op ubuntu werkt het wel, op windows helaas niet.

De functie formatCurrency heb ik zelf geschreven (is wellicht ook niet relevant):
def formatCurrency(string):
try:
currency = '';
parts = str(string).split(',');
z = 0;
for  i in parts :
currency += str(i)
z=z+1;
if(z < len(parts)):
currency += '.'

if(len(currency)):
return float("%0.2f" % float(currency));
else:
return float(0.00);
except ValueError, msg:
print str(msg);
return float(0.00)

Die functie zorgt ervoor dat een bedrag wordt goed gezet voor local.currency (i.v.m. type, comma's ipv punt, etc).

Weet iemand een oplossing voor dit probleem?
Groet, Koen
« Laatst bewerkt op: 2011/09/02, 19:32:13 door Koen Bokern »

Offline Rachid

  • Lid
    • rachidbm
    • Mijn blog
Re: PyQt cross-platform textcoderingen (UTF-8)
« Reactie #1 Gepost op: 2011/09/01, 14:52:40 »
Ik heb hier niet zoveel ervaring mee in Python. Maar voor je "currency" probleem/uitdaging zijn er  locales. http://www.google.com/search?q=python+locales 

Misschien kun je met "currency symbol" wel het euroteken gelijk goed weergeven?
Ben je ook blij dat Ubuntu zo toegankelijk en gratis is, en wil je graag net als ik iets terugdoen, kijk dan eens rond bij mwanzo, dé poort naar het bijdragen aan Ubuntu en haar gemeenschap!

Re: PyQt cross-platform textcoderingen (UTF-8)
« Reactie #2 Gepost op: 2011/09/01, 14:59:39 »
Dat dacht ik ook, dus vandaar dat ik locale.currency() gebruik (zie code). Maar:

price = locale.currency(formatCurrency(price))

item.setText(9, price) // onbekend teken op ubuntu, windows niet getest.
item.setText(9, unicode(price)) // UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
item.setText(9, unicode(QString.fromUtf8(price))) // correct op ubuntu, onbekend teken op windows.
item.setText(9, QString.fromUtf8(price)) // correct op ubuntu, onbekend teken op windows.

Offline commandoline

  • LoCo-contact
    • marten-de-vries
    • Marten-de-Vries.nl
Re: PyQt cross-platform textcoderingen (UTF-8)
« Reactie #3 Gepost op: 2011/09/01, 15:18:04 »
Over het algemeen is het handig om de volgende regel aan te houden: 'Gebruik intern Unicode, en de- of encodeer alleen in- en uitvoer.' Dat zou in jouw geval op het volgende neerkomen:

- Een QString is het equivalent van unicode() in Python, en dankzij PyQt4 kan je ze simpel in elkaar omzetten: unicode(QString) en andersom kan ook, hoewel je ook gewoon je unicode object aan de Qt functie mee kan geven als er om een QString gevraagd wordt.
- Strings in je broncode (bijv. teken = u"é") kan je alleen opgeven als je bovenin het programmabestand aangeeft welke encoding het bestand gebruikt, ik begin ieder serieus programma zo (UTF-8 is standaard als je een tekstbestand aanmaakt op Ubuntu):
#! /usr/bin/env python
# -*- coding: utf-8 -*-
- Als je data importeert of exporteert, converteer je het direct naar unicode strings. Daarvoor zul je wél de encoding moeten meegeven, bijv: unicode(file.open("data.xml").read(), "UTF-8") om te importeren.

Het lijkt momenteel misschien wat gek om overal intern unicode strings te gebruiken, maar als je bedenkt dat het in Python 3 de standaard strings zijn geworden, valt dat opeens wel mee.

http://diveintopython3.org/strings.html (Engels) vind ik zelf erg informatief, let wel op dat ze daar over Python 3 spreken. Daar is 'bytes' wat nu string is en is 'string' wat nu 'unicode' is.
« Laatst bewerkt op: 2011/09/01, 15:20:08 door commandoline »

Re: PyQt cross-platform textcoderingen (UTF-8)
« Reactie #4 Gepost op: 2011/09/01, 15:27:24 »
Elk python bestand begin ik met:
#!/usr/bin/python
# -*- coding: utf-8 -*-

Als ik een euro teken hardcoded met QString.fromUtf8() gebruik dan werkt het ook.
Als ik je goed begrijp dan is unicode(QString) eigenlijk nutteloos?

Wat ik eens ga proberen is:
locale.setlocale(locale.LC_ALL, '')
Bedankt voor de nuttige info :)

Edit
Ok zoals ik had gedacht had het local.setLocale(...) geen effect.

Na even zoeken ben ik hierop gekomen:
http://doc.qt.nokia.com/4.8-snapshot/qsystemlocale.html

QSystemLocale::CurrencySymbol en QSystemLocale::CurrencyToString zouden wellicht een oplossing kunnen bieden. Echter er is een probleem, ik zit nog op Qt 4.7. (4.8.0 is nog beta als ik het goed begrijp)


« Laatst bewerkt op: 2011/09/01, 16:19:39 door Koen Bokern »

Offline commandoline

  • LoCo-contact
    • marten-de-vries
    • Marten-de-Vries.nl
Re: PyQt cross-platform textcoderingen (UTF-8)
« Reactie #5 Gepost op: 2011/09/01, 17:58:59 »
Als ik een euro teken hardcoded met QString.fromUtf8() gebruik dan werkt het ook.
Ik zie eigenlijk geen reden om een QString aan te maken, aangezien Qt overal waar in de documentatie QString staat, ook gewoon een python string (unicode of niet) accepteert:
symbol = u"€"
label = QtGui.QLabel(symbol)
Zeker omdat de QString in Python eigenlijk maar een onding is, je kunt 'm bijvoorbeeld niet in een functie gooien die gebruik maakt van een aantal string methods als .split() en .strip().

Als ik je goed begrijp dan is unicode(QString) eigenlijk nutteloos?
Het omgekeerde is nutteloos, maar dit heeft best z'n toepassingen:
input = lineEdit.text() #input is een QString
unicode(input).split("/") #input.split("/") had niet gewerkt, dus eerst converteren naar unicode

Wat ik eens ga proberen is:
locale.setlocale(locale.LC_ALL, '')
Bedankt voor de nuttige info :)

Edit
Ok zoals ik had gedacht had het local.setLocale(...) geen effect.

Na even zoeken ben ik hierop gekomen:
http://doc.qt.nokia.com/4.8-snapshot/qsystemlocale.html

QSystemLocale::CurrencySymbol en QSystemLocale::CurrencyToString zouden wellicht een oplossing kunnen bieden. Echter er is een probleem, ik zit nog op Qt 4.7. (4.8.0 is nog beta als ik het goed begrijp)
Wat wil je nou precies doen hiermee?

Re: PyQt cross-platform textcoderingen (UTF-8)
« Reactie #6 Gepost op: 2011/09/01, 20:32:45 »
Niet voor het een of ander, maar QString ondersteund ook split() en een hoop andere methods. Dus ik zie niet in waarom een QString een onding zou moeten zijn. Veel dingen die Qt ondersteund kunnen ook met gewoon python, maar worden die dingen dan overbodig?

Citaat van: commandoline
Wat wil je nou precies doen hiermee?
Dat heb ik in mijn eerste post uitgelegd? Ik zoek een oplossing om het euro-teken correct te weergeven op Windows en op Ubuntu. Op Ubuntu heb ik geen problemen hiermee, op Windows werkt het niet zoals het hoort.

En aangezien ik graag wil dat mijn probleem wordt opgelost dan wel niet wordt omzeilt, probeer ik zelf ook door te zoeken naar mogelijkheden i.p.v. alleen te wachten. QSystemLocale zag ik als potentiële oplossing, echter is het pas in >= 4.8.0

Offline commandoline

  • LoCo-contact
    • marten-de-vries
    • Marten-de-Vries.nl
Re: PyQt cross-platform textcoderingen (UTF-8)
« Reactie #7 Gepost op: 2011/09/01, 21:06:58 »
Niet voor het een of ander, maar QString ondersteund ook split() en een hoop andere methods. Dus ik zie niet in waarom een QString een onding zou moeten zijn. Veel dingen die Qt ondersteund kunnen ook met gewoon python, maar worden die dingen dan overbodig?
Mijn punt was dat veel functies (ook in de standard libraries) niet geschikt zijn voor gebruik met een QString. Dat is logisch, QString is aan Qt gebonden. Maar, als je liever de Qt functies gebruikt (dan bijv. die in de standard library) is daar natuurlijk niets mis mee. :)

Citaat van: commandoline
Wat wil je nou precies doen hiermee?
Dat heb ik in mijn eerste post uitgelegd? Ik zoek een oplossing om het euro-teken correct te weergeven op Windows en op Ubuntu. Op Ubuntu heb ik geen problemen hiermee, op Windows werkt het niet zoals het hoort.

En aangezien ik graag wil dat mijn probleem wordt opgelost dan wel niet wordt omzeilt, probeer ik zelf ook door te zoeken naar mogelijkheden i.p.v. alleen te wacithten. QSystemLocale zag ik als potentiële oplossing, echter is het pas in >= 4.8.0

OK, ik begreep niet precies waarom je QSystemLocale erbij haalde bij een encodingprobleem, nu wel. Ik heb even een testscriptje geschreven, en denk dat ik nu begrijp waarom het wel werkt op het ene en niet op het andere systeem.
from PyQt4 import QtCore, QtGui
import locale

locale.setlocale(locale.LC_ALL, "") #vereist volgens de documentatie
price = locale.currency(3.45) #prijs berekenen, dit geeft de prijs volgens mij terug in de encoding die hoort bij de huidige 'locale', ook al kon ik dat nergens in de docs vinden
price = unicode(price, locale.getpreferredencoding()) #hier doe ik de conversie naar unicode m.b.v. die preferred encoding

app = QtGui.QApplication([])
item = QtGui.QLabel()
item.setText(price) #rechtstreeks een unicode object in Qt stoppen :)
item.show()
app.exec_()
Getest op Windows en Ubuntu. Het punt zou dan dus de wisselende encoding zijn die locale.currency() teruggeeft. Ik kan niet wachten tot de overstap op Python 3 rond is :P.

Re: PyQt cross-platform textcoderingen (UTF-8)
« Reactie #8 Gepost op: 2011/09/01, 21:51:27 »
Citaat van: commandoline
OK, ik begreep niet precies waarom je QSystemLocale erbij haalde bij een encodingprobleem, nu wel.
Aha, vandaar :P

Zelf heb ik ook even een testscript gemaakt. Die wisselende encoding, ja dat zal denk ik het probleem zijn. Dit script heb ik getest en werkt zowel op windows als op ubuntu:

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import locale,sys

locale.setlocale(locale.LC_ALL, '')

class test(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
String = locale.currency(10.0)
String = QString.fromUtf8(String).replace(u'\ufffd', u'\u20AC')

w = QLabel(self)
w.setText(String)
w.show()

app = QApplication(sys.argv)
f = test()
f.show()
sys.exit(app.exec_())
Kennelijk werkt het zo dus wel. Ik zal morgen nog eens verder kijken, nu snel vertrekken voordat ik te laat kom op het werk :P

Offline commandoline

  • LoCo-contact
    • marten-de-vries
    • Marten-de-Vries.nl
Re: PyQt cross-platform textcoderingen (UTF-8)
« Reactie #9 Gepost op: 2011/09/02, 12:47:11 »
Het werkt, maar waarschijnlijk niet op alle systemen die in omloop zijn (want je vervangt maar één symbool). Iemand heeft dat hier geanalyseerd:

http://stackoverflow.com/questions/4082645/using-python-2-xs-locale-module-to-format-numbers-and-currency

De conclusie: 'In all cases, the workaround is to use only str objects when calling these methods, get a str result, and decode it using the encoding obtained by locale.getlocale()[1]' (dus niet getpreferredencoding() zoals ik eerder zei.)

Re: PyQt cross-platform textcoderingen (UTF-8)
« Reactie #10 Gepost op: 2011/09/02, 16:13:09 »
Hmm... die link heeft me in ieder geval wat wijzer gemaakt. De code "print locale.getlocale()[1]" geeft 1252. En in die tabel staat bij het euro-teken '20AC', zoals ik in mijn string.replace() heb gebruikt. Nu begrijp ik in ieder geval al iets meer.

 
Citaat van: commandoline
Het werkt, maar waarschijnlijk niet op alle systemen die in omloop zijn (want je vervangt maar één symbool). Iemand heeft dat hier geanalyseerd:
In principe maakt het niet zoveel uit, omdat alleen mn moeke de applicatie gaat gebruiken om een hoop uren aan administratie te besparen. Vandaar is windows -> NL belangrijk. Ubuntu -> NL uiteraard ook omdat ik de app aan het schrijven ben :P

Maar het zou sowieso wel mooier zijn om het cross-platform / cross-language te hebben.

Nu heb ik weer even getest met behulp van die link:
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import locale,sys

locale.setlocale(locale.LC_ALL, '')

class test(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)

print locale.getlocale()[1]

char = locale.localeconv()['currency_symbol'].decode(locale.getlocale()[1])
String = char+locale.currency(10.0,False)
String = QString.fromUtf8(String)

w = QLabel(self)
w.setText(String)
w.show()

app = QApplication(sys.argv)
f = test()
f.show()
sys.exit(app.exec_())
Op Ubuntu werkt dat weer, op windows niet. Ook heb ik zitten kijken naar .encode() maar volgens mij lukt het daar ook niet mee. Ik vind het toch wel een beetje frustrerend dat python dit niet kan. Maar je had het over python 3, die zou het dus wellicht wel juist doen?


Edit:
Opeens kreeg ik een idee. Namelijk zelf de unicode codes definiëren.
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import locale,sys

locale.setlocale(locale.LC_ALL, '')

def currency_symbol(ics=False):
sym = { 'AUD':u'\u0024','BWP':u'\u0050','CAD':u'\u0024','DKK':u'\u006b\u0072','GBP':u'\u00A3',\
'HKD':u'\u0024','EUR':u'\u20AC','NGN':u'\u20a6','PHP':u'\u20b1','USD':u'\u0024',\
'ZAR':u'\u0052','ZWD':u'\u005a\u0024','JPY':u'\u00a5'}

if not ics:
ics = locale.localeconv()['int_curr_symbol'].strip()

if ics in sym:
return sym[ics]
return "?"


class test(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
String = currency_symbol() + locale.currency(10.0,False)
w = QLabel(self)
w.setText(String)
w.show()

app = QApplication(sys.argv)
f = test()
f.show()
sys.exit(app.exec_())
Die code werkt zowel op Windows als op Ubuntu. Daarnaast zijn diverse currency-signs van verschillende landen op te vragen. Als je 'print' gebruikt dan krijg je wel een error (tenzei dat je QString().toAscii() gebruikt), maar Qt kan het wel juist weergeven. Ik denk dat dit de oplossing is, tenzei dat iemand deze laaste code lariekoek vind :P
« Laatst bewerkt op: 2011/09/02, 17:17:02 door Koen Bokern »

Offline commandoline

  • LoCo-contact
    • marten-de-vries
    • Marten-de-Vries.nl
Re: PyQt cross-platform textcoderingen (UTF-8)
« Reactie #11 Gepost op: 2011/09/02, 19:18:28 »
Het eerste voorbeeldje van je ging fout omdat je aannam dat 'String' UTF-8 is, maar dat is op Windows niet zo, want op Windows is het resultaat van locale.currency() gecodeerd als Windows-1252 zoals je al aangaf. Je tweede voorbeeld is als het werkt een oplossing, maar de encoding opvragen en die gebruiken om 'String' om te zetten naar unicode vind ik persoonlijk simpeler (getest onder Windows en Ubuntu):
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import locale,sys

locale.setlocale(locale.LC_ALL, '')

class test(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)

print locale.getlocale()[1]

string = locale.currency(10.0)
unicodeString = unicode(string, encoding=locale.getlocale()[1])

w = QLabel(self)
w.setText(unicodeString)
w.show()

app = QApplication(sys.argv)
f = test()
f.show()
sys.exit(app.exec_())

Re: PyQt cross-platform textcoderingen (UTF-8)
« Reactie #12 Gepost op: 2011/09/02, 19:31:45 »
Aha, dus op die manier pas je locale.getlocale()[1] toe :)

Nice, morgen eens testen. Bedankt voor de hulp! Ik geef dit topic maar een 'opgelost' tag, heb nu namelijke genoeg mogelijke oplossingen :)