Mehrere Delimiter / Separator beim CSV - Import

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
Natrium
User
Beiträge: 15
Registriert: Montag 13. April 2020, 16:13

Guten Abend zusammen,

Ich habe folgenden Code zum Import einer CSV Datei:

pfad() ist gleich der Pfad zur CSV Datei.

Code: Alles auswählen

import csv

    def importierung():
        try:
            with open(pfad(), encoding="ascii", newline="") as csv_datei:
                ergebnis = {key: values for key, *values in csv.reader(csv_datei)}
                return ergebnis
        except:
                print("Das war leider nicht erfolgreich, bitte korrigieren und Pfad erneut eingeben.")
                return importierung()
Klappt alles soweit auch reibungslos. Die Werte in der CSV Datei werden derzeit nach dem default delimiter sprich dem Komma getrennt.

Ich würde gerne dass als Delimiter sowohl das "," als auch weitere delimiter - sprich z.B. ";" möglich sind, sodass es in der CSV - Datei egal ist ob die Trennung mit , oder ; erfolgt.

Kann ich das einfach als "or" in die Funktion einfügen sprich -> delimiter "," or ";" ?

Danke für kurze Hilfe & einen schönen Abend.
lg
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Natrium: Die Einrückung der Funktion sieht komisch aus.

Das nackte ``except`` ohne mindestens eine konkrete Ausnahme die da behandelt werden soll ist falsch. Weder der Benutzer noch der Programmierer bekommt hier mit *warum* eine Ausnahme ausgelöst wurde. Das macht Fehlersuche unnötig schwer.

Der rekursive Aufruf von `importierung()` ist falsch. Rekursion ist kein geeignetes Mittel einfache Schleifen zu ersetzen.

Weder `importierung` noch `pfad` sind gute, sinnvolle Funktionsnamen, weil beides keine Tätigkeiten sind. Insbesondere `pfad` wäre ein guter Name für einen Pfad. Den man nun dank der Funktion nicht mehr dafür verwenden kann.

CSV-Dateien haben nur *ein* Trennzeichen. Sollten sie mehrere/verschiedene haben, sind es halt keine CSV-Dateien mehr. Und nein, Programmiersprachen sind kein Wunschkonzert wo man einfach schreibt was man meint und hofft, dass es dann das auch bedeutet. ``or`` ist ein binärer Operator mit je einem Operanden links und rechts und ein Ausdruck ``a or b`` wird entsprechend der Semantik von ``or`` ausgwertet. Entweder zu `a` oder zu `b`, je nachdem ob `a` ”wahr” oder ”unwahr” ist.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
nezzcarth
User
Beiträge: 1764
Registriert: Samstag 16. April 2011, 12:47

Falls du die Erzeugung der Datei beeinflussen kannst, sorg' doch dafür, dass es nur einen Trenner gibt. Man kann auch versuchen, die Datei vor dem Parsen zu Normalisieren, aber dabei muss man sehr aufpassen, dass nicht Trennzeichen, die zum eigentlichen Inhalt gehören, mit normalisiert werden.
Natrium
User
Beiträge: 15
Registriert: Montag 13. April 2020, 16:13

__blackjack__ hat geschrieben: Mittwoch 20. Mai 2020, 16:42 @Natrium: Die Einrückung der Funktion sieht komisch aus.

Das nackte ``except`` ohne mindestens eine konkrete Ausnahme die da behandelt werden soll ist falsch. Weder der Benutzer noch der Programmierer bekommt hier mit *warum* eine Ausnahme ausgelöst wurde. Das macht Fehlersuche unnötig schwer.

Der rekursive Aufruf von `importierung()` ist falsch. Rekursion ist kein geeignetes Mittel einfache Schleifen zu ersetzen.

Weder `importierung` noch `pfad` sind gute, sinnvolle Funktionsnamen, weil beides keine Tätigkeiten sind. Insbesondere `pfad` wäre ein guter Name für einen Pfad. Den man nun dank der Funktion nicht mehr dafür verwenden kann.

CSV-Dateien haben nur *ein* Trennzeichen. Sollten sie mehrere/verschiedene haben, sind es halt keine CSV-Dateien mehr. Und nein, Programmiersprachen sind kein Wunschkonzert wo man einfach schreibt was man meint und hofft, dass es dann das auch bedeutet. ``or`` ist ein binärer Operator mit je einem Operanden links und rechts und ein Ausdruck ``a or b`` wird entsprechend der Semantik von ``or`` ausgwertet. Entweder zu `a` oder zu `b`, je nachdem ob `a` ”wahr” oder ”unwahr” ist.
Vielen Dank erst einmal für eure beiden Antworten.

Das Try / Except in der Funktion funtkioniert eigentlich einwandfrei - Wird ein falscher Dateipfad eingegeben, muss der User diesen Input korrigieren und einen korrekten Dateipfad eingeben. Da dies ja die Ausnahmefälle sind und diese Funktion maximal wohl 3 Mal wiederholt wird, war ich der Meinung, dass auch ein rekursiver Aufruf okay ist.

Vielen Dank für den Tip - Die Funktionsnamen werde ich noch entsprechend ändern. :)


Hauptfaktor bei den Trennzeichen ist, dass ich vermeiden möchte, dass der User, welcher die CSV-Datei erstellt, mit falschen Trennzeichen arbeitet.

Sollte der User also ";" statt "," verwenden in der CSVDatei, würde ich das gerne im Vorraus abfangen - sodass "," und ";" beide als Trennzeichen gültig wären.

Ich hätte gedacht, dass csv - Modul hätte bereits eine solche Möglichkeit (multiple delimiters) integriert, was dann aber nicht der Fall zu sein scheint.

Der Operator "or" war auch eher als Beispiel gedacht, um das Problem zu erklären, ist schon klar, dass es innerhalb der Parameter nicht angewendet werden kann.

Frage ist jetzt, wie kann ich verhindern, bzw. dass das Programm reagiert, wenn der User falsche Trennzeichen verwendet?

Derzeit ist es so, dass wenn in der CSV z.B. steht "A;B" - A und B nicht getrennt werden sondern das ganze als String "A;B" komplett übernommen wird.

Danke schon mal!
nezzcarth
User
Beiträge: 1764
Registriert: Samstag 16. April 2011, 12:47

Ich finde, du versuchst den Personen, die das benutzen sollen, zu viel abzunehmen. Wenn das Eingabeformat CSV ist, bedeutet das streng genommen eigentlich, dass ein Komma als Trenner verwendet werden muss, denn dafür steht das 'C' nun mal (ich weiß, dass die Realität anders aussieht). Man kann zusätzlich noch (zum Beispiel als Kommandozeilenparameter), die Option geben, manuell einen alternativen Trenner zu definieren und das machen die meisten Programme, die CSV verarbeiten, auch. Aber viel weiter würde ich nicht gehen. Ein Format ist dazu gedacht, dass man sich daran hält. Daher würde ich davon absehen, Features wie das Erraten von Trennern, mehrere Trenner, etc. einzubauen (das geht irgendwann schief und ist dann kaum nachvollziehbar). CSV, TSV und ähnliche Formate werden ja meist mit Programmen erzeugt und nicht per Hand eingegeben, insofern kann man da eine gewisse Konsistenz schon voraussetzen.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Man kann versuchen den Trenner zu erraten, je mehr du über den Inhalt weißt z.B. wieviele Spalten es gibt, so besser funktioniert sowas. In der Praxis ist es aber dennoch sinnvoll die Kontrolle darüber dem Benutzer zu überlassen, zumindest optional. Wenn du dir andere Programme die mit CSV Dateien arbeiten wie z.B. Google Sheets oder Excel, wirst du feststellen dass die es auch so machen.
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Natrium: Das ``try``/``except`` funktioniert nicht einwandfrei. Egal welche Ausnahme auftritt, die Ausgabe an den Benutzer verrät nicht was denn nicht erfolgreich war, und das auch bei Sachen die der Benutzer gar nicht korrigieren kann. Dieses ``except`` behandelt *jede* Ausnahme so, und das ist schlicht falsch. Niemals nackte ``except``\s, ausser man löst die Ausnahme nach der Behandlung wieder aus und die Behandlung beinhaltet so etwas wie das Protokollieren der Ausnahme samt Traceback, damit diese Informationen nicht verloren gehen.

Rekursive Aufrufe für nicht-rekursive Probleme sind in Sprachen ohne garantierte „tail call optimization“ nicht okay. Warum sollten sie? Eine Schleife hat a) die Probleme nicht, ist b) einfach zu schreiben, und ist c) auch deutlicher, denn die kann man als Leser nicht so leicht überlesen wie ein rekursiver Aufruf irgendwo *im* eigentlichen Schleifenkörper.

Im CSV-Modul gibt es die `Sniffer`-Klasse. Aber da die natürlich auch falsch raten kann, sollte man dem Benutzer dann auch immer die Möglichkeit geben die Werte explizit anzugeben wenn er es besser weiss.

Die Idee beispielsweise einfach ";" und "," als Trenner zuzulassen, ist keine gute, weil ein grosses Anwendungsgebiet von CSV-Dateien Daten mit Zahlen sind, und gerade im deutschsprachigen Raum wird dabei oft das Komma als Dezimaltrenner und nicht als Feldtrenner verwendet.

Ansonsten könntest Du vielleicht noch eine Plausibiltätsprüfung einbauen. Also beispielsweise ob die Werte im Ergebnis ausschliesslich leere Listen sind und in dem Fall eine Warnung ausgeben.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Natrium
User
Beiträge: 15
Registriert: Montag 13. April 2020, 16:13

Ah okay, verstehe den Hintergrund bei der Except Funktion - egal, was schief läuft, es wird immer das except ausgelöst & der User weiß nicht, wo der Fehler liegt.
Danke :)

Wäre es denn möglich bei meiner oben genannten Funktion einen Trenner als Variable zu definieren, welcher der User vorher durch Input deklariert?

Sprich der User gibt als Trenner ";" an und dieses wird dann als Trennzeichen in der Funktion verwendet?

Das würde das ganze natürlich deutlich sinniger gestalten.

Lg
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Natrium: Ja klar wäre das möglich. Warum sollte es nicht möglich sein?
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Natrium
User
Beiträge: 15
Registriert: Montag 13. April 2020, 16:13

__blackjack__ hat geschrieben: Donnerstag 21. Mai 2020, 12:02 @Natrium: Ja klar wäre das möglich. Warum sollte es nicht möglich sein?
Das macht ja definitv am meisten Sinn, dann fällt die ganzere obere Geschichte ja komplett weg.

Weisst du auf die Schnelle, wo das Trennzeichen in dem CSV Import angegeben wird?

Thanks :)
Natrium
User
Beiträge: 15
Registriert: Montag 13. April 2020, 16:13

> Vergesst es, habs natürlich selbst hinbekommen, nach ein wenig Recherche :)

Vielen Dank an alle - Habe jetzt durch euch eine sinnige Lösung für das Problem gefunden.

Macht ja auch x-Mal mehr Sinn das Trennzeichen einfach durch den User abzufragen.

Thanks & schönen Abend
Antworten