免責事項
2014-12-01更新:以下の回答は、CSVの非常に具体的な1つの形式に対してのみ機能します。コメントでDGが正しく指摘しているように、このソリューションは、CSVのRFC 4180定義に適合せず、MS Excel形式にも適合しません。このソリューションは、文字列タイプの混合を含む入力の1つの(非標準)CSV行を解析する方法を単に示しています。ここで、文字列はエスケープされた引用符とコンマを含む場合があります。
非標準のCSVソリューション
austincheneyが正しく指摘しているように、エスケープ文字を含む可能性のある引用符付き文字列を適切に処理したい場合は、文字列を最初から最後まで解析する必要があります。また、OPは「CSV文字列」が実際に何であるかを明確に定義していません。最初に、有効なCSV文字列の構成要素とその個々の値を定義する必要があります。
指定:「CSV文字列」の定義
この説明では、「CSV文字列」は0個以上の値で構成され、複数の値はコンマで区切られています。各値は次のもので構成されます。
- 二重引用符で囲まれた文字列。(エスケープされていない単一引用符が含まれる場合があります。)
- 一重引用符で囲まれた文字列。(エスケープされていない二重引用符が含まれる場合があります。)
- 引用符で囲まれていない文字列。(引用符、カンマ、バックスラッシュを含めることはできません。)
- 空の値。(すべて空白の値は空と見なされます。)
ルール/メモ:
- 引用符で囲まれた値にはカンマが含まれる場合があります。
- 引用符で囲まれた値には、エスケープされたすべてのものを含めることができます
'that\'s cool'
。
- 引用符、カンマ、またはバックスラッシュを含む値は引用符で囲む必要があります。
- 先頭または末尾の空白を含む値は引用符で囲む必要があります。
- バックスラッシュはすべてから削除されます:
\'
単一引用符で囲まれた値。
\"
二重引用符で囲まれた値のすべてからバックスラッシュが削除されます。
- 引用符で囲まれていない文字列は、先頭と末尾のスペースが削除されます。
- カンマ区切りには、隣接する空白がある場合があります(無視されます)。
検索:
有効なCSV文字列(上記で定義)を文字列値の配列に変換するJavaScript関数。
解決:
このソリューションで使用される正規表現は複雑です。(IMHO)すべての重要な正規表現は、多くのコメントとインデントを含むフリースペースモードで表示する必要があります。残念ながら、JavaScriptはフリースペースモードを許可しません。したがって、このソリューションによって実装される正規表現は、最初にネイティブの正規表現構文で表示されます(Pythonの便利なr'''...'''
raw-multi-line-string構文を使用して表現されます)。
まず、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文字列の1つの値を照合します。一致がなくなるまで(そしてすべての値が解析されるまで)繰り返し適用されます。
有効なCSV文字列から1つの値を解析する正規表現:
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.
"""
この正規表現が一致しない特別なケース値が1つあることに注意してください-その値が空の場合の最後の値。この特別な「空の最後の値」のケースは、以下のjs関数によってテストされ、処理されます。
CSV文字列を解析するJavaScript関数:
// 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;
};
入力と出力の例:
次の例では、中括弧を使用してを区切ってい{result strings}
ます。(これは、先頭/末尾のスペースと長さ0の文字列を視覚化するのに役立ちます。)
// 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] = {} */
その他の注意事項:
このソリューションでは、CSV文字列が「有効」である必要があります。たとえば、引用符で囲まれていない値にバックスラッシュや引用符を含めることはできません。たとえば、次のCSV文字列は無効です。
var invalid1 = "one, that's me!, escaped \, comma"
サブストリングは一重引用符または二重引用符で囲まれた値として表される可能性があるため、これは実際には制限ではありません。このソリューションは、「カンマ区切り値」の1つの可能な定義のみを表すことにも注意してください。
編集:2014-05-19:免責事項を追加しました。
編集:2014-12-01:免責事項を先頭に移動しました。