PHuV schrieb:
Natürlich ist das CSV hier nicht gut designt. Ich habe jahrelang mit diversen Datenformaten gearbeitet (XML, EDI wie EDIFACT, Sedas, IDOC, Ansi X12, ....), glaub mir, ich kenne mich damit sehr gut aus. Du wirst bei Uneindeutigkeit IMMER das Problem der Verarbeitung bzw. Parsierbarkeit haben.
Welche Uneindeutigkeit? Das Feld in der CSV vom TE ist
eindeutig ein Feld, da es durch den Feldbegrenzer
"
eingegrenzt wird. Innerhalb eines Feldbegrenzers kann ganz regulär ein Feldtrenner
[,;\t]
eingesetzt werden. Mit bash und cut kommst du da nicht zum Ziel, mit Regex genauso nicht. Also schnapp dir einfach nen ordentlichen Parser und gut ist.
In
RFC4180 werden auch die Regeln des Formats vorgegeben.
- jede Zeile ein Datensatz
Code:
aaa,bbb,ccc CRLF
zzz,yyy,xxx CRLF
- EOF CRLF ist optional
Code:
aaa,bbb,ccc CRLF
zzz,yyy,xxx
- Header sind optional
Code:
field_name,field_name,field_name CRLF
aaa,bbb,ccc CRLF
zzz,yyy,xxx CRLF
- jedes Feld durch Komma
,
getrennt
- Felder optional durch Quotes eingegrenzt
Code:
"aaa","bbb","ccc" CRLF
zzz,yyy,xxx
- Felder mit CRLF, Quotes und Kommas sollten in Quotes gesetzt werden
Code:
"aaa","b CRLF
bb","ccc" CRLF
zzz,yyy,xxx
- wenn Quotes im Feld vorkommen, müssen diese doppelt escaped werden
Regel 6 bedeutet also, dass der Datensatz
Code:
spalte1,spalte2,"Nachname, Vorname",spalte4,usw
komplett gültig ist. Der TE hat ergo ne valide CSV vor sich liegen.
Funfact: Übrigens gibts in der ASCII-Tabelle bereits Steuerzeichen für Group
0x1d
und Record
0x1e
Separator (zusätzlich zum Unit Separator
0x1f
), die man auch verwenden könnte. Das gilt aber eben nur für den Export, über welchen der TE keine Kontrolle hat und zudem auch nicht standardkonform sind.
PHuV schrieb:
Einspruch, Du hast permanent Probleme damit. Durfte ich erst wieder mit einer YAML-Datei erleben, wo ein Kennwort $ enthielt, und Gitlab in der Konfiguration das trotz Escape nicht gefressen hatte. Genau das gleiche Drama mit Tomcat Konfiguration, Java und Proxykonfiguration wie Passwörtern und Co. mit " \/& usw. auf Linux wie Windows Ebene, wenn das allerlei von Konsolen und Startscripten weggefrühstückt wird.
Wie du an meinen Aufrufen oben siehst, haben PowerShells
ConvertTo-Csv
und
ConvertFrom-Csv
, sowie csvtool keine Probleme damit.
YAML ist ne ganz andere Story oder wie war das mit Norwegens ISO2 Code, welcher als Boolean geparst wird? Nicht umsonst gibts YAML Strict. Raw Strings in YAML werden mit Hochkommas eingegrenzt. Ein ordentlicher Parser sollte das unterscheiden können, wenn er auch
NO
als
false
parsen kann. Es gibt halt einen Unterschied zwischen
'foo$bar'
und
"foo$bar"
. Hochkommas sollten so geparst werden, wie sie da zu sehen sind, Anführungszeichen erhalten zusätzliches Parsing.
http://yaml-online-parser.appspot.com/
Zeigt mir auch an was ich erwarte:
Code:
- 'foo $ bar'
- 'foo \$ bar'
- 'foo \\$ bar'
- "foo \\$ bar"
- "foo \\\\$ bar"
- "foo \\\\\\$ bar"
[
"foo $ bar",
"foo \\$ bar",
"foo \\\\$ bar",
"foo \\$ bar",
"foo \\\\$ bar",
"foo \\\\\\$ bar"
]
YAML ist nun aber auch kein sinnvolles Format zur Serialisierung oder zum Transport. TOML ist imho ne noch perfidere Krankheit. Vor zwei Tagen von
KDL gelesen...
Das hat aber primär nichts mit dem Format, sondern rein dem Parser zu tun. Es gibt auch genug
.env
-Parser, die bei
die Quotes erhalten. Manche entfernen sie. Manche ersetzen noch Variablen...
PHuV schrieb:
Dann darf eben das ; nicht im Feld auftauchen, ganz einfach, oder es muß als Ausnahme entsprechend korrekt markiert werden (Escape).
"ganz einfach" ist eben Hanebüchen. Dann übermittel ich eben Artikelbeschreibungen ohne Newlines als Wall of Text im Fließtext. Artikeleigenschaften? Klar, entfernen wir den Trenner, kann der Fernseher halt statt
OLED, 55", HDMI
eben
OLED 55 HDMI
. OLED in Version 55 oder 55 HDMI Slots? Achso, 55 Zoll, OLED und HDMI...
Gut, wenn der Empfänger das nicht verarbeiten "kann" - mir egal, sein Pech. Wenn ich die Daten aber so erhalte, kann ich da natürlich rumpfuschen, "bis mein System damit umgehen kann" oder man nutzt einfach nen regulären Parser, der das schlucken kann und korrekt verarbeitet. Cloud, Kubernetes, Docker, 128-Core-CPUs, aber heute stolpert man immer noch über CSVs, weil man diese mit bash und cut verarbeiten will, da man zu faul ist sich nen simplen Parser zu suchen. ¯\
(ツ)/¯ Wegen nem Feldbegrenzer
"
mal eben alle Quotes aus dem Text schmeißen...
Dein Einwand hat aber ein weiteres Problem. Weshalb escapen? Ein Parser, der keine Escape-Sequenzen kennt, knallt dir einfach ne weitere Spalte rein und endet die vorherige Spalte mit
\
(so wie im Falle von
cut
). Dann hast du wahlweise bei zehn Feldern, wovon fünf gequotet sind und je ein Komma enthalten 15 Felder und die Daten passen vorn und hinten nicht mehr. Ggf. knallt es dann in der Warenwirtschaft, Backend, Frontend, ... (je nachdem wie du es weiterverarbeitest) und du hast keine Ahnung wieso und bist am Debuggen von 5 Mio Datensätzen und das alles nur, weil du statt nem ordentlichen Parser
cut
verwendet hast. Mit viel Glück, Geschick und weiterer Pfuscherei könnte man damit auch gleich untersuchen, ob dadurch irgendwas exploitbar ist, weil deine "12. Spalte" (die nicht existiert), in irgend einem Szenario einen Payload darstellen kann. Und schon bist du durch deinen dilletantischen Import einer CSV gehackt worden.
Das erinnert mich grad an
The Perl Jam: Exploiting a 20 Year-old Vulnerability
Ne Spalte mehr oder weniger macht ja nichts...
SQL-Injections funktionieren auf die selbe Art und Weise und die existieren massenhaft, genauso wie auch XSS. Und wie verlinkt bricht sich selbst Perl dabei ein Bein ab - nicht auf identische Weise, aber durch das selbe Prinzip.
PHuV schrieb:
Daher, gutes Datenformat: alles ist eindeutig, und bei der Datenerstellung wird darauf korrekt geachtet.
Sein obiges Beispiel ist eindeutig. Es gibt in CSV ja noch genauso nicht nur die Backslash-Escape-Variante (eigentlich überhaupt nicht), sondern auch einfach doppelte Feldtrenner (die eigentlich korrekte Weise nach RFC).
PowerShell und csvtool funktionieren bspw. nur mit doppelten Feldtrennern.
3.csv
Code:
1 "2 \" 2.1" 3 4
5 6 7 8
9 10 11 12
| 4.csv
Code:
1 "2 "" 2.1" 3 4
5 6 7 8
9 10 11 12
|
Code:
$ csvtool -t ' ' col 2 3.csv
2 \
6
10
$ csvtool -t ' ' col 2 4.csv
"2 "" 2.1"
6
10
|
Code:
$ .\csv.ps1
a b c d
- - - -
1 2 \ 2.1"
5 6 7 8
9 10 11 12
1 2 " 2.1 3 4
5 6 7 8
9 10 11 12
|
Aber abseits von CSV ist bei XML bspw. überhaupt nicht "klar" (also eigentlich schon, aber kaum ein Parser/Serializer unterstützt es korrekt), wann
<![CDATA[ ... ]]>
gesetzt wird. Einige lassen es weg, andere lassen es weg und escapen, manche Serializer geben mir keine Möglichkeit CDATA nicht zu setzen, sondern serialisieren am liebsten jedes Feld damit, manche Parser schlucken es, manche ignorieren es komplett, manche übernehmen es mit in den Wert...
Also nur weil ein Format "eindeutig" ist, heißt es nicht, dass jede Implementierung auch korrekt arbeitet, da je nachdem der übliche Pfusch am Bau vorhanden ist. Ich hab auch schon genug Fälle gesehen, wo man manuell JSON serialisiert hat (nicht mit
json_encode()
,
json.dump()
,
JsonConvert.SerializeObject()
,
JSON.stringify()
...) und dann selbst an Strings gefummelt wurde... Oder SQL durch String-Operationen zusammensetzen, statt nen Query Builder zu benutzen.
Wenn man es nicht besser weiß - gut, kann man nachhelfen. Wer es weiß aber nicht will - typischer Kurpfuscher.
PHuV schrieb:
Wenn man das verstanden hat, kann man es auch entsprechend von den Datenerzeugern einfordern, oder man macht, wie eben vorgeschlagen, eine mehrstufige Bearbeitung, um aus einem schlechten Dateiformat ein gutes zu bauen.
Oder man nutzt eben einen ordentlichen Parser und kein Gefrickel mit bash, cut, Regex, string replace, ... und verfälscht die Daten im Vorlauf nicht. :O
Aber der TE hat halt das Problem der bash. Die ist für solche Fälle nunmal gänzlich ungeeignet, außer er will jedes Feld jedes Datensatzes einzeln auslesen und auswerten (mittels bspw. csvtool). Also einfach ne geeignetere Shell (PowerShell) nehmen oder mindestens ne Scriptsprache (PHP, Python, Node, ...) anwerfen womit er die Datei ordentlich parsen kann, damit es nicht zu Fehlern kommt.