Zrzeczenie się
Aktualizacja 2014-12-01: Poniższa odpowiedź działa tylko dla jednego bardzo konkretnego formatu CSV. Jak słusznie wskazała DG w komentarzach , rozwiązanie to nie pasuje do definicji CSV RFC 4180, a także nie pasuje do formatu Microsoft Excel. To rozwiązanie po prostu pokazuje, jak można przeanalizować jeden (niestandardowy) wiersz danych wejściowych CSV, który zawiera mieszankę typów ciągów, gdzie łańcuchy mogą zawierać cudzysłowy i przecinki.
Niestandardowe rozwiązanie CSV
Jak słusznie wskazuje austincheney , naprawdę musisz przeanalizować łańcuch od początku do końca, jeśli chcesz poprawnie obsługiwać ciągi w cudzysłowie, które mogą zawierać znaki ucieczki. Ponadto PO nie definiuje jasno, czym naprawdę jest „ciąg CSV”. Najpierw musimy zdefiniować, co stanowi prawidłowy ciąg CSV i jego poszczególne wartości.
Biorąc pod uwagę: Definicja „Ciąg CSV”
Na potrzeby tej dyskusji „ciąg CSV” składa się z zera lub większej liczby wartości, przy czym wiele wartości jest oddzielonych przecinkiem. Każda wartość może składać się z:
- Ciąg w cudzysłowie (może zawierać pojedyncze cudzysłowy bez znaku zmiany znaczenia).
- Ciąg znaków w pojedynczym cudzysłowie (może zawierać cudzysłowy bez znaku zmiany znaczenia).
- Ciąg bez cudzysłowu ( nie może zawierać cudzysłowów, przecinków ani ukośników odwrotnych).
- Pusta wartość. (Wszystkie białe znaki są uważane za puste).
Zasady / uwagi:
- Cytowane wartości mogą zawierać przecinki.
- Cytowane wartości mogą zawierać znaki ucieczki, np
'that\'s cool'
.
- Wartości zawierające cudzysłowy, przecinki lub ukośniki odwrotne muszą być cytowane.
- Wartości zawierające początkowe lub końcowe białe znaki muszą być cytowane.
- Odwrotny ukośnik jest usuwany ze wszystkich:
\'
w pojedynczych cudzysłowach.
- Odwrotny ukośnik jest usuwany ze wszystkich:
\"
w podwójnych cudzysłowach.
- Ciągi bez cudzysłowów są usuwane z wszelkich spacji wiodących i końcowych.
- Separator przecinka może mieć sąsiadujące białe znaki (które są ignorowane).
Odnaleźć:
Funkcja JavaScript, która konwertuje prawidłowy ciąg CSV (zgodnie z powyższą definicją) na tablicę wartości ciągów.
Rozwiązanie:
Wyrażenia regularne używane w tym rozwiązaniu są złożone. I (IMHO) wszystkie nietrywialne wyrażenia regularne powinny być prezentowane w trybie wolnych odstępów z dużą ilością komentarzy i wcięć. Niestety JavaScript nie pozwala na tryb wolnego odstępu. W związku z tym wyrażenia regularne zaimplementowane przez to rozwiązanie są najpierw prezentowane w natywnej składni wyrażeń regularnych (wyrażonych za pomocą przydatnej składni r'''...'''
surowych, wieloliniowych ciągów znaków Pythona ).
Najpierw tutaj jest wyrażenie regularne, które potwierdza, że łańcuch CVS spełnia powyższe wymagania:
Wyrażenie regularne do walidacji „ciągu CSV”:
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.
"""
Jeśli ciąg pasuje do powyższego wyrażenia regularnego, to jest to prawidłowy ciąg CSV (zgodnie z wcześniej określonymi regułami) i może być analizowany przy użyciu następującego wyrażenia regularnego. Następujące wyrażenie regularne jest następnie używane do dopasowania jednej wartości z ciągu CSV. Jest stosowany wielokrotnie, aż nie zostaną znalezione żadne dopasowania (a wszystkie wartości zostaną przeanalizowane).
Wyrażenie regularne do analizowania jednej wartości z prawidłowego ciągu CSV:
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.
"""
Zwróć uwagę, że istnieje jedna wartość przypadku specjalnego, której to wyrażenie regularne nie pasuje - ostatnia wartość, gdy ta wartość jest pusta. Ten specjalny przypadek „pustej ostatniej wartości” jest testowany i obsługiwany przez następującą funkcję JavaScript.
Funkcja JavaScript do analizy ciągu CSV:
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;
if (!re_valid.test(text)) return null;
var a = [];
text.replace(re_value,
function(m0, m1, m2, m3) {
if (m1 !== undefined) a.push(m1.replace(/\\'/g, "'"));
else if (m2 !== undefined) a.push(m2.replace(/\\"/g, '"'));
else if (m3 !== undefined) a.push(m3);
return '';
});
if (/,\s*$/.test(text)) a.push('');
return a;
};
Przykładowe dane wejściowe i wyjściowe:
W poniższych przykładach nawiasy klamrowe służą do oddzielania {result strings}
. (Ma to pomóc w wizualizacji spacji wiodących / końcowych i ciągów o zerowej długości).
var test = "'string, duppi, du', 23, lala";
var a = CSVtoArray(test);
var test = "";
var a = CSVtoArray(test);
var test = ",";
var a = CSVtoArray(test);
var test = "'one','two with escaped \' single quote', 'three, with, commas'";
var a = CSVtoArray(test);
var test = '"one","two with escaped \" double quote", "three, with, commas"';
var a = CSVtoArray(test);
var test = " one , 'two' , , ' four' ,, 'six ', ' seven ' , ";
var a = CSVtoArray(test);
Dodatkowe uwagi:
To rozwiązanie wymaga, aby ciąg CSV był „prawidłowy”. Na przykład, wartości nienotowane nie mogą zawierać backslashy lub cytaty, np następujący ciąg CSV nie obowiązuje:
var invalid1 = "one, that's me!, escaped \, comma"
W rzeczywistości nie jest to ograniczenie, ponieważ każdy podłańcuch może być reprezentowany jako wartość w pojedynczym lub podwójnym cudzysłowie. Należy również zauważyć, że to rozwiązanie reprezentuje tylko jedną możliwą definicję „wartości rozdzielanych przecinkami”.
Edytuj historię
- 2014-05-19: Dodano wyłączenie odpowiedzialności.
- 2014-12-01: Przeniesiono wyłączenie odpowiedzialności na górę.