Отказ от ответственности
Обновление 2014-12-01: ответ ниже работает только для одного очень конкретного формата CSV. Как правильно указал DG в комментариях , это решение не соответствует определению CSV RFC 4180, а также не соответствует формату Microsoft Excel. Это решение просто демонстрирует, как можно проанализировать одну (нестандартную) входную строку CSV, которая содержит сочетание типов строк, где строки могут содержать экранированные кавычки и запятые.
Нестандартное решение CSV
Как правильно указывает Остинчени , вам действительно нужно проанализировать строку от начала до конца, если вы хотите правильно обрабатывать строки в кавычках, которые могут содержать экранированные символы. Кроме того, OP четко не определяет, что такое «строка CSV» на самом деле. Сначала мы должны определить, что составляет действительную строку CSV и ее отдельные значения.
Дано: "Строка CSV" Определение
Для целей этого обсуждения «строка CSV» состоит из нуля или более значений, где несколько значений разделены запятой. Каждое значение может состоять из:
- Строка в двойных кавычках (может содержать неэкранированные одинарные кавычки).
- Строка в одинарных кавычках (может содержать неэкранированные двойные кавычки).
- Строка без кавычек ( не может содержать кавычек, запятых или обратных косых черт).
- Пустое значение. (Все пробелы считаются пустыми.)
Правила / Примечания:
- Значения в кавычках могут содержать запятые.
- Значения в кавычках могут содержать что угодно, например
'that\'s cool'
.
- Значения, содержащие кавычки, запятые или обратную косую черту, должны быть заключены в кавычки.
- Значения, содержащие начальные или конечные пробелы, должны быть заключены в кавычки.
- Обратная косая черта удаляется со всех:
\'
в одинарных кавычках.
- Обратная косая черта удаляется со всех:
\"
в двойных кавычках.
- Строки без кавычек удаляются от начальных и конечных пробелов.
- Разделитель запятой может иметь смежные пробелы (которые игнорируются).
Найти:
Функция JavaScript, которая преобразует действительную строку CSV (как определено выше) в массив строковых значений.
Решение:
Регулярные выражения, используемые в этом решении, сложны. И (IMHO) все нетривиальные регулярные выражения должны быть представлены в режиме свободного интервала с большим количеством комментариев и отступов. К сожалению, JavaScript не поддерживает режим свободного интервала. Таким образом, регулярные выражения, реализованные в этом решении, сначала представлены в собственном синтаксисе регулярных выражений (выраженном с помощью удобного синтаксиса Python для r'''...'''
необработанных многострочных строк).
Во-первых, вот регулярное выражение, которое проверяет соответствие строки CVS указанным выше требованиям:
Регулярное выражение для проверки "строки 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.
"""
Если строка соответствует указанному выше регулярному выражению, то эта строка является допустимой строкой CSV (в соответствии с ранее указанными правилами) и может быть проанализирована с использованием следующего регулярного выражения. Следующее регулярное выражение затем используется для сопоставления одного значения из строки CSV. Он применяется многократно, пока больше не будет найдено совпадений (и все значения не будут проанализированы).
Регулярное выражение для синтаксического анализа одного значения из допустимой строки 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.
"""
Обратите внимание, что есть одно значение особого случая, которому это регулярное выражение не соответствует - самое последнее значение, когда это значение пусто. Этот специальный случай «пустое последнее значение» проверяется и обрабатывается следующей функцией JavaScript.
Функция JavaScript для анализа строки 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;
};
Пример ввода и вывода:
В следующих примерах фигурные скобки используются для разделения {result strings}
. (Это помогает визуализировать начальные / конечные пробелы и строки нулевой длины.)
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);
Дополнительные примечания:
Это решение требует, чтобы строка CSV была «действительной». Например, котирующиеся значения не могут содержать обратную косую черту или кавычки, например , следующая строка CSV является не действительным:
var invalid1 = "one, that's me!, escaped \, comma"
На самом деле это не ограничение, потому что любая подстрока может быть представлена как значение в одинарных или двойных кавычках. Также обратите внимание, что это решение представляет только одно возможное определение для «значений, разделенных запятыми».
Редактировать историю
- 2014-05-19: Добавлен отказ от ответственности.
- 2014-12-01: Заявление об отказе от ответственности перемещено наверх.