locale hin, locale her, was ist nun richtig?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mechanicalStore
User
Beiträge: 166
Registriert: Dienstag 29. Dezember 2009, 00:09

Zugegeben habe ich das bisher nicht gebraucht und daher nur wenig mit beschaeftigt. Aktuell wandle ich string nach floar. Folgender Test:

Code: Alles auswählen

# test.csv
pos-x;pos-y;pos-z
23,009;-14,234;8,123
-1.298,55;0,6;4.233,776

Code: Alles auswählen

#!/usr/bin/env python

import locale
import csv

locale.setlocale(locale.LC_ALL, 'de_DE.utf8')

def main():
        x_collecrtion = []
        with open('test.csv', newline='') as csvfile:
            reader = csv.DictReader(csvfile, delimiter=';')
            for row in reader:
                print(row['pos-x'], row['pos-y'], row['pos-z'])
                x_collecrtion.append(locale.atof(row['pos-x']))
                # x_collecrtion.append(float(row['pos-x']))
        print(x_collecrtion)

if __name__ == '__main__':
    main()
Bei der csv sind die Nachkommastellen hinter einem ','(Komma) und die Tausender Trennzeichen mit einem '.'(Punkt), also de_DE konform. Das Umwandeln per float funktioniert damit nicht , nur per locale.atof. In dem Fall mit de_DE.utf8. Bei en_US kommen dann Zahlen mit Faktor 1000 multipliziert, das Gleiche mit umgekehrtem Format und de_DE, was ja auch logisch erscheint. Das Encoding der csv spielt dabei offenbar ueberhaupt keine Rolle, der Effekt ist immer der gleiche (selbst bei setlocale de_DE.utf8 mit ISO-8859-1 als Encoding).

Auf was bezieht sich die setlocale ueberhaupt? Einstellung in der Umgebung? Nur auf das Script zur Laufzeit bezogen? Nur auf locale.atof bezogen?

Warum funktioniert das Umwandeln per float in dem Fall nicht?

Was sagt das utf8 in de_DE.utf8 aus (s.O., scheint sich am eigentlichen Encoding nicht zu stoeren)?

Wenn ich nun die csv mal so oder mal so bekomme, wie kann ich das Format auf jeden Fall sicher erkennen und umwandeln?
Benutzeravatar
snafu
User
Beiträge: 6830
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Der Sinn von locale aus der Doku (https://docs.python.org/3/library/locale.html) zitiert:
The POSIX locale mechanism allows programmers to deal with certain cultural issues in an application, without requiring the programmer to know all the specifics of each country where the software is executed.
Einsatzzweck ist also die Anpassung des Programmverhaltens gemäß der potenziell unbekannten Spracheinstellungen des Benutzersystems. Daher findet man auch meistens keine spezifische Angabe, sondern stattdessen so etwas:

Code: Alles auswählen

locale.setlocale(locale.LC_ALL, '')
Dies aktiviert die o. g. Umgebungseinstellungen und sie gelten dann bis zur nächsten Änderung für die Laufzeit des Python-Programms. Sie haben, wie du schon bemerkt hast, keinen Einfluss float() und ähnliches, sondern gelten nur für spezifischen Code, der diese Einstellungen ausliest, wie z. B. die Funktionen des locale-Moduls. Beachte dass diese Änderung alle Module betrifft, die im Interpreter eingebunden sind. Wenn also eine Drittbibliothek ebenfalls auf sprachspezifische Einstellungen zugreift, dann beeinflusst dein setlocale()-Aufruf auch dort das Verhalten.

Wenn man es robuster haben möchte, würde man hierfür das babel-Paket verwenden:

Code: Alles auswählen

from babel.numbers import parse_decimal

parse_decimal('-1.298,55', locale='de')
Oder wenn man kein zusätzliches Paket installieren möchte oder kann, dann wäre auch eine eigene Funktion möglich:

Code: Alles auswählen

from decimal import Decimal

def parse_german_decimal(string):
    return Decimal(
        string.replace(".", "")
              .replace(",", ".")
    )
Antworten