ubuntuusers.de

parsen von csv-Dateien

Status: Gelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

linuxbasher

Anmeldungsdatum:
6. März 2010

Beiträge: 44

Hallo zusammen!

Ich möchte Tabellen im Textformat (hier "csv"-Dateien von OpenOffice) mit bash (oder awk oder perl) weiter bearbeiten. Jede Zeile enthält mehrere Felder, die durch ein Trennzeichen wie z.B. ein Komma getrennt sind. Jedes Feld könnte das Trennzeichen selbst enthalten, weswegen es in Anführungszeichen eingeschlossen ist. Eine Zeile sieht wie folgt aus:

"Meier, Heinz", "Straße", "12345 Stadt"

Ich möchte solche Zeilen in ein Array einlesen. Mit (bash)

read -d "," -a A

geht es offensichtlich nicht, weil Anführungszeichen nicht berücksichtigt werden. Gibt es eine einfache und elegante Möglichkeit, solche Textzeilen in bash / awk / perl unter Berücksichtigung der Anführungszeichen korrekt zu parsen und in ein Array einzulesen?

Grüße

linuxbasher

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17608

Wohnort: Berlin

Geht das:

sed 's/", "/;/g'  adr.csv  | read -d ";" -a A 

Lunar

Anmeldungsdatum:
17. März 2006

Beiträge: 5792

Ohne Perl zu kennen, bin ich mir vollkommen sicher, dass es in den unendlichen Weiten des CPAN ein oder mehrere Module zum Parsen von CSV-Dateien gibt. Einfach mal suchen … ☺

tzzaetaynzz

Avatar von tzzaetaynzz

Anmeldungsdatum:
9. Mai 2009

Beiträge: 265

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

linuxbasher schrieb:

Hallo zusammen!

Ich möchte Tabellen im Textformat (hier "csv"-Dateien von OpenOffice) mit bash (oder awk oder perl) weiter bearbeiten. Jede Zeile enthält mehrere Felder, die durch ein Trennzeichen wie z.B. ein Komma getrennt sind. Jedes Feld könnte das Trennzeichen selbst enthalten, weswegen es in Anführungszeichen eingeschlossen ist.

Und wenn das Feld Anführungszeichen enthält?

linuxbasher

(Themenstarter)

Anmeldungsdatum:
6. März 2010

Beiträge: 44

user unknown schrieb:

Geht das:

sed 's/", "/;/g'  adr.csv  | read -d ";" -a A 

Eigentlich nicht, weil auch keine saubere Lösung.

Ich hatte mich vertan. Zeilen sehen aus wie folgt:

"Meier, Heinz","Straße","12345 Stadt"

tzzaetaynzz schrieb:

http://search.cpan.org/dist/Text-CSV/

Danke für den Hinweis. Die Seite kannte ich noch nicht. Das Modul scheint tatsächlich ein "Alleskönner" zu sein, allerdings nicht einfach zu bedienen.

Ich lasse diesen Thread noch etwas offen, weil ich noch auf halbwegs einfache Tricks unter awk und bash warte. Ich benutze noch einen Workaround mit awk (Quotes entfernen, Doppelquotes durch einfache ersetzen usw.).

Weil die bash selbst das Quoten gut beherrscht, habe ich auch mit Konstrukten wie

declare -a A
eval "A=($zeile)"

herumexperimentiert, aber die sind sehr gefährlich.

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Die große Unbekannte ist hier doch imho, was Du denn mit den Daten vorhast? Sollte das Problem zu komplex für die Bash sein, wieso dann nicht alles in Perl schreiben? Wo liegt hier der Vorteil der Bash?

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

linuxbasher schrieb:

Danke für den Hinweis. Die Seite kannte ich noch nicht. Das Modul scheint tatsächlich ein "Alleskönner" zu sein, allerdings nicht einfach zu bedienen.

Wie bitte!? Ich habe keinen Plan von Perl, und die Nutzung des Moduls ist nach einen kurzen Blick auf die Synopsis sonnenklar. Einfacher wird's nicht.

linuxbasher

(Themenstarter)

Anmeldungsdatum:
6. März 2010

Beiträge: 44

Lysander schrieb:

Die große Unbekannte ist hier doch imho, was Du denn mit den Daten vorhast? Sollte das Problem zu komplex für die Bash sein, wieso dann nicht alles in Perl schreiben? Wo liegt hier der Vorteil der Bash?

Es ist ein eigenes Quick-and-(not-too)-dirty-Skript, mit dem ich mein Adressbuch von OpenOffice (als csv-Datei gespeichert) auslese, filtere und als einfache HTML-Seite nach meinem Gusto darstelle. Es ist recht einfach, funktioniert einwandfrei, ist aber halt nicht sauber programmiert.

Da das Problem, des Quotens, des Escapens und des Parsens von csv-Dateien viel allgemeiner ist, wollte ich hier nur nach ein paar eleganten Programiertricks fragen, falls es die gibt. Perl mit dem genannten Modul oder einem selbst geschriebenen Parser ist mir hierfür etwas zu overkill.

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

Nochmal: Dieses Modul ist absolut trivial zu benutzen. Wenn Dir das zu viel Aufwand ist, dann lass das Script wie es ist. Eine nennenswerte Verbesserung wird Dir dann nämlich ohnehin nicht gelingen.

Lunar

Anmeldungsdatum:
17. März 2006

Beiträge: 5792

Der eleganteste Programmiertrick ist hier, Perl mit diesem Modul zu nutzen, einfacher wird es nicht. Wenn Dir das zu "overkill" ist, kann Dir nicht mehr geholfen werden …

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Hi linuxbasher,

noch Willkommen auf dem Forum !

Sind die Felder in Deiner csv immer in Gänsefüßchen gekapselt ?
Und immer mit Komma getrennt, ohne Leerzeichen ?

Dann würde es doch ausreichen, wenn Du awk einsetzt, und das Trennsymbol auf "," festlegst.
Dann noch das " am Anfang und am Ende gelöscht, und die Felder stehen ganz brav in den Feldern $1, $2, usw. von awk
... ich glaube, so würde ich das machen.

track

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

linuxbasher schrieb:

Es ist ein eigenes Quick-and-(not-too)-dirty-Skript, mit dem ich mein Adressbuch von OpenOffice (als csv-Datei gespeichert) auslese, filtere und als einfache HTML-Seite nach meinem Gusto darstelle. Es ist recht einfach, funktioniert einwandfrei, ist aber halt nicht sauber programmiert.

Das würde mich reizen mal in Python3 mit jinja 2.3 zu realisieren ☺ Das geht sicher recht kurz und elegant...

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

Ich hab gerade mal etwas zusammengestrickt. Mit Text::CSV und HTML::EasyTags ist das wirklich einfach.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/perl
use strict;
use Text::CSV;
use HTML::EasyTags;

my $html = HTML::EasyTags->new();
my $csv = Text::CSV->new({binary => 1});

print $html->start_html('Mein Adressbuch');
print $html->table_start;

while (my $row = $csv->getline(\*STDIN)) {
    print $html->tr_start;
    foreach (@$row) {
        print $html->td(text => $_);
    }
    print $html->tr_end;
}

print $html->table_end;
print $html->end_html;

Ordentlich geärgert habe ich mich aber heute über cpan(1). Der Mist ist nicht in der Lage, Devel::REPL zu installieren und ist zudem der mit großem Abstand benutzerunfreundlichste Paketmanager, den ich kenne.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Eine awk-Variante dazu habe ich da auch noch mal schnell zusammengestrickt:

#! /usr/bin/awk -f

### Skript  csv2html  konvertiert eine comma-separated list in eine einfache html-Tabelle

BEGIN {	print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">";
	print "<TABLE BORDER=2>";
	}

 {	sub("^\"","<TR><TD>",$0);
	gsub("\",\"","</TD><TD>",$0);
	sub("\"$","</TD></TR>",$0);
	print $0;
	}

END {	print "</TABLE>";	}

Das Skript muss natürlich erst "ausführbar" gemacht werden, (einfach per Rechtsklick - Eigenschaften - [Rechte] - [√] Ausführen)
dann erfolgt der Aufruf mit:

./csv2html  liste.csv  >  liste.html


track

csv2html (358 Bytes)
Download csv2html
Antworten |