Haftungsausschluss
01.12.2014 Update: Die folgende Antwort funktioniert nur für ein ganz bestimmtes CSV-Format. Wie DG in den Kommentaren korrekt ausgeführt hat, passt diese Lösung NICHT zur RFC 4180-Definition von CSV und auch NICHT zum MS Excel-Format. Diese Lösung zeigt einfach, wie eine (nicht standardmäßige) CSV-Eingabezeile analysiert werden kann, die eine Mischung von Zeichenfolgentypen enthält, wobei die Zeichenfolgen maskierte Anführungszeichen und Kommas enthalten können.
Eine nicht standardmäßige CSV-Lösung
Wie austincheney richtig hervorhebt, müssen Sie die Zeichenfolge wirklich von Anfang bis Ende analysieren, wenn Sie Zeichenfolgen in Anführungszeichen, die möglicherweise maskierte Zeichen enthalten, richtig verarbeiten möchten. Außerdem definiert das OP nicht klar, was eine "CSV-Zeichenfolge" wirklich ist. Zuerst müssen wir definieren, was eine gültige CSV-Zeichenfolge und ihre einzelnen Werte ausmacht.
Gegeben: "CSV String" Definition
Für die Zwecke dieser Diskussion besteht eine "CSV-Zeichenfolge" aus null oder mehr Werten, wobei mehrere Werte durch ein Komma getrennt sind. Jeder Wert kann bestehen aus:
- Eine Zeichenfolge in doppelten Anführungszeichen. (Kann einfache Anführungszeichen enthalten.)
- Eine einfache Zeichenfolge in Anführungszeichen. (Kann doppelte Anführungszeichen enthalten.)
- Eine Zeichenfolge ohne Anführungszeichen. (Darf KEINE Anführungszeichen, Kommas oder Backslashes enthalten.)
- Ein leerer Wert. (Ein Leerzeichenwert wird als leer betrachtet.)
Regeln / Hinweise:
- Anführungszeichen können Kommas enthalten.
- Zitierte Werte können Escape-alles enthalten, z
'that\'s cool'
.
- Werte, die Anführungszeichen, Kommas oder Backslashes enthalten, müssen in Anführungszeichen gesetzt werden.
- Werte, die führende oder nachfolgende Leerzeichen enthalten, müssen in Anführungszeichen gesetzt werden.
- Der Backslash wird von allen entfernt:
\'
in einfachen Anführungszeichen.
- Der Backslash wird von allen entfernt:
\"
in doppelten Anführungszeichen.
- Nicht in Anführungszeichen gesetzte Zeichenfolgen werden von führenden und nachfolgenden Leerzeichen abgeschnitten.
- Das Komma-Trennzeichen kann benachbarte Leerzeichen enthalten (die ignoriert werden).
Finden:
Eine JavaScript-Funktion, die eine gültige CSV-Zeichenfolge (wie oben definiert) in ein Array von Zeichenfolgenwerten konvertiert.
Lösung:
Die von dieser Lösung verwendeten regulären Ausdrücke sind komplex. Und (IMHO) alle nicht trivialen regulären Ausdrücke sollten im Freiraummodus mit vielen Kommentaren und Einrückungen dargestellt werden. Leider erlaubt JavaScript keinen Freiraummodus. Daher werden die von dieser Lösung implementierten regulären Ausdrücke zunächst in nativer Regex-Syntax dargestellt (ausgedrückt mit Pythons praktischer Syntax: r'''...'''
Raw-Multi-Line-String).
Hier ist zunächst ein regulärer Ausdruck, der bestätigt, dass eine CVS-Zeichenfolge die oben genannten Anforderungen erfüllt:
Regex zur Validierung einer "CSV-Zeichenfolge":
re_valid = r"""
# Validate a CSV string having single, double or un-quoted values.
^ # Anchor to start of string.
\s* # Allow whitespace before value.
(?: # Group for value alternatives.
'[^'\\]*(?:\\[\S\s][^'\\]*)*' # Either Single quoted string,
| "[^"\\]*(?:\\[\S\s][^"\\]*)*" # or Double quoted string,
| [^,'"\s\\]*(?:\s+[^,'"\s\\]+)* # or Non-comma, non-quote stuff.
) # End group of value alternatives.
\s* # Allow whitespace after value.
(?: # Zero or more additional values
, # Values separated by a comma.
\s* # Allow whitespace before value.
(?: # Group for value alternatives.
'[^'\\]*(?:\\[\S\s][^'\\]*)*' # Either Single quoted string,
| "[^"\\]*(?:\\[\S\s][^"\\]*)*" # or Double quoted string,
| [^,'"\s\\]*(?:\s+[^,'"\s\\]+)* # or Non-comma, non-quote stuff.
) # End group of value alternatives.
\s* # Allow whitespace after value.
)* # Zero or more additional values
$ # Anchor to end of string.
"""
Wenn eine Zeichenfolge mit dem obigen regulären Ausdruck übereinstimmt, ist diese Zeichenfolge eine gültige CSV-Zeichenfolge (gemäß den zuvor angegebenen Regeln) und kann mit dem folgenden regulären Ausdruck analysiert werden. Der folgende reguläre Ausdruck wird dann verwendet, um einen Wert aus der CSV-Zeichenfolge abzugleichen. Es wird wiederholt angewendet, bis keine Übereinstimmungen mehr gefunden werden (und alle Werte analysiert wurden).
Regex, um einen Wert aus einer gültigen CSV-Zeichenfolge zu analysieren:
re_value = r"""
# Match one value in valid CSV string.
(?!\s*$) # Don't match empty last value.
\s* # Strip whitespace before value.
(?: # Group for value alternatives.
'([^'\\]*(?:\\[\S\s][^'\\]*)*)' # Either $1: Single quoted string,
| "([^"\\]*(?:\\[\S\s][^"\\]*)*)" # or $2: Double quoted string,
| ([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*) # or $3: Non-comma, non-quote stuff.
) # End group of value alternatives.
\s* # Strip whitespace after value.
(?:,|$) # Field ends on comma or EOS.
"""
Beachten Sie, dass es einen Sonderfallwert gibt, mit dem dieser reguläre Ausdruck nicht übereinstimmt - den allerletzten Wert, wenn dieser Wert leer ist. Dieser spezielle Fall "leerer letzter Wert" wird von der folgenden js-Funktion getestet und behandelt.
JavaScript-Funktion zum Parsen von CSV-Zeichenfolgen:
// Return array of string values, or NULL if CSV string not well formed.
function CSVtoArray(text) {
var re_valid = /^\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*(?:,\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*)*$/;
var re_value = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;
// Return NULL if input string is not well formed CSV string.
if (!re_valid.test(text)) return null;
var a = []; // Initialize array to receive values.
text.replace(re_value, // "Walk" the string using replace with callback.
function(m0, m1, m2, m3) {
// Remove backslash from \' in single quoted values.
if (m1 !== undefined) a.push(m1.replace(/\\'/g, "'"));
// Remove backslash from \" in double quoted values.
else if (m2 !== undefined) a.push(m2.replace(/\\"/g, '"'));
else if (m3 !== undefined) a.push(m3);
return ''; // Return empty string.
});
// Handle special case of empty last value.
if (/,\s*$/.test(text)) a.push('');
return a;
};
Beispiel für Ein- und Ausgabe:
In den folgenden Beispielen werden geschweifte Klammern verwendet, um die zu begrenzen {result strings}
. (Dies dient zur Visualisierung von führenden / nachfolgenden Leerzeichen und Zeichenfolgen mit der Länge Null.)
// Test 1: Test string from original question.
var test = "'string, duppi, du', 23, lala";
var a = CSVtoArray(test);
/* Array hes 3 elements:
a[0] = {string, duppi, du}
a[1] = {23}
a[2] = {lala} */
// Test 2: Empty CSV string.
var test = "";
var a = CSVtoArray(test);
/* Array hes 0 elements: */
// Test 3: CSV string with two empty values.
var test = ",";
var a = CSVtoArray(test);
/* Array hes 2 elements:
a[0] = {}
a[1] = {} */
// Test 4: Double quoted CSV string having single quoted values.
var test = "'one','two with escaped \' single quote', 'three, with, commas'";
var a = CSVtoArray(test);
/* Array hes 3 elements:
a[0] = {one}
a[1] = {two with escaped ' single quote}
a[2] = {three, with, commas} */
// Test 5: Single quoted CSV string having double quoted values.
var test = '"one","two with escaped \" double quote", "three, with, commas"';
var a = CSVtoArray(test);
/* Array hes 3 elements:
a[0] = {one}
a[1] = {two with escaped " double quote}
a[2] = {three, with, commas} */
// Test 6: CSV string with whitespace in and around empty and non-empty values.
var test = " one , 'two' , , ' four' ,, 'six ', ' seven ' , ";
var a = CSVtoArray(test);
/* Array hes 8 elements:
a[0] = {one}
a[1] = {two}
a[2] = {}
a[3] = { four}
a[4] = {}
a[5] = {six }
a[6] = { seven }
a[7] = {} */
Zusätzliche Bemerkungen:
Diese Lösung erfordert, dass die CSV-Zeichenfolge "gültig" ist. Beispielsweise dürfen nicht in Anführungszeichen gesetzte Werte keine Backslashes oder Anführungszeichen enthalten, z. B. ist die folgende CSV-Zeichenfolge NICHT gültig:
var invalid1 = "one, that's me!, escaped \, comma"
Dies ist keine wirkliche Einschränkung, da jede Unterzeichenfolge entweder als einfacher oder doppelter Wert dargestellt werden kann. Beachten Sie auch, dass diese Lösung nur eine mögliche Definition für: "Kommagetrennte Werte" darstellt.
Bearbeiten: 2014-05-19: Haftungsausschluss hinzugefügt.
Bearbeiten: 2014-12-01: Haftungsausschluss nach oben verschoben.