次の正規表現がcsv文字列を行単位で分割できる場合。これは、(引用符/二重引用符の間にIE)CSV値の中に含まれている改行文字をスキップするように適合させることができる方法引用符で囲まれた改行をスキップしてCSV文字列を分割する
var lines = csv.split(/\r|\r?\n/g);
?
例:
2,"Evans & Sutherland","230-132-111AA",,"Visual","P\r\nCB",,1,"Offsite",\r\n
私はスキップしようとしている部分が中に含まれる改行です:
2,"Evans & Sutherland","230-132-111AA",,"Visual","P
CB",,1,"Offsite",
あなたがそれを見ていない場合は、ここで目に見える改行付きバージョンがあります"PCB"エントリの真ん中です。
更新:
私はおそらく前にこれを言及してきたはずですが、これはjquery-csvと呼ばれる専用のCSV解析するライブラリの一部です。より良いコンテキストを提供するために、私は以下の現在のパーサー実装を追加しました。
ここでエントリを検証して解析するためのコード(すなわち、1つの行)です:
$.csvEntry2Array = function(csv, meta) {
var meta = (meta !== undefined ? meta : {});
var separator = 'separator' in meta ? meta.separator : $.csvDefaults.separator;
var delimiter = 'delimiter' in meta ? meta.delimiter : $.csvDefaults.delimiter;
// build the CSV validator regex
var reValid = /^\s*(?:D[^D\\]*(?:\\[\S\s][^D\\]*)*D|[^SD\s\\]*(?:\s+[^SD\s\\]+)*)\s*(?:S\s*(?:D[^D\\]*(?:\\[\S\s][^D\\]*)*D|[^SD\s\\]*(?:\s+[^SD\s\\]+)*)\s*)*$/;
reValid = RegExp(reValid.source.replace(/S/g, separator));
reValid = RegExp(reValid.source.replace(/D/g, delimiter));
// build the CSV line parser regex
var reValue = /(?!\s*$)\s*(?:D([^D\\]*(?:\\[\S\s][^D\\]*)*)D|([^SD\s\\]*(?:\s+[^SD\s\\]+)*))\s*(?:S|$)/g;
reValue = RegExp(reValue.source.replace(/S/g, separator), 'g');
reValue = RegExp(reValue.source.replace(/D/g, delimiter), 'g');
// Return NULL if input string is not well formed CSV string.
if (!reValid.test(csv)) {
return null;
}
// "Walk" the string using replace with callback.
var output = [];
csv.replace(reValue, function(m0, m1, m2) {
// Remove backslash from any delimiters in the value
if (m1 !== undefined) {
var reDelimiterUnescape = /\\D/g;
reDelimiterUnescape = RegExp(reDelimiterUnescape.source.replace(/D/, delimiter), 'g');
output.push(m1.replace(reDelimiterUnescape, delimiter));
} else if (m2 !== undefined) {
output.push(m2);
}
return '';
});
// Handle special case of empty last value.
var reEmptyLast = /S\s*$/;
reEmptyLast = RegExp(reEmptyLast.source.replace(/S/, separator));
if (reEmptyLast.test(csv)) {
output.push('');
}
return output;
};
注:私はまだテストしていないが、私は、私はおそらくメインに最後の試合を組み込むことができると思いますが、分割/コールバック。それは作品がthis answerを見てみましょうreges方法
$.csv2Array = function(csv, meta) {
var meta = (meta !== undefined ? meta : {});
var separator = 'separator' in meta ? meta.separator : $.csvDefaults.separator;
var delimiter = 'delimiter' in meta ? meta.delimiter : $.csvDefaults.delimiter;
var skip = 'skip' in meta ? meta.skip : $.csvDefaults.skip;
// process by line
var lines = csv.split(/\r\n|\r|\n/g);
var output = [];
for(var i in lines) {
if(i < skip) {
continue;
}
// process each value
var line = $.csvEntry2Array(lines[i], {
delimiter: delimiter,
separator: separator
});
output.push(line);
}
return output;
};
の内訳については:
このは、スプリット・バイ・ラインの部分を行うコードです。私のものはやや適合したバージョンです。一重引用符と二重引用符のマッチングを統合して、1つのテキスト区切り文字にマッチさせ、区切り文字/区切り文字を動的にしました。それはEntiriesを検証する素晴らしい仕事をしますが、私が上に追加した行分割ソリューションはかなり虚弱で、私が上で説明したエッジケースで壊れています。
私は、有効なエントリを抽出して(エントリパーサに渡す)文字列を見回す、または解析に失敗した行を示すエラーを返す不良データで失敗するソリューションを探しています。
更新:
- 0:
splitLines: function(csv, delimiter) { var state = 0; var value = ""; var line = ""; var lines = []; function endOfRow() { lines.push(value); value = ""; state = 0; }; csv.replace(/(\"|,|\n|\r|[^\",\r\n]+)/gm, function (m0){ switch (state) { // the start of an entry case 0: if (m0 === "\"") { state = 1; } else if (m0 === "\n") { endOfRow(); } else if (/^\r$/.test(m0)) { // carriage returns are ignored } else { value += m0; state = 3; } break; // delimited input case 1: if (m0 === "\"") { state = 2; } else { value += m0; state = 1; } break; // delimiter found in delimited input case 2: // is the delimiter escaped? if (m0 === "\"" && value.substr(value.length - 1) === "\"") { value += m0; state = 1; } else if (m0 === ",") { value += m0; state = 0; } else if (m0 === "\n") { endOfRow(); } else if (m0 === "\r") { // Ignore } else { throw new Error("Illegal state"); } break; // un-delimited input case 3: if (m0 === ",") { value += m0; state = 0; } else if (m0 === "\"") { throw new Error("Unquoted delimiter found"); } else if (m0 === "\n") { endOfRow(); } else if (m0 === "\r") { // Ignore } else { throw new Error("Illegal data"); } break; default: throw new Error("Unknown state"); } return ""; }); if (state != 0) { endOfRow(); } return lines; }
それが取ったすべてがラインスプリッタのための4つの状態であるエントリ
- 1の開始:以下が引用されています
- 2:2番目の見積もりが発生しました
- 3:以下は引用されていません
これはほぼ完全なパーサーです。私の使用事例では、私は単にCSVデータを処理するためのより洗練されたアプローチを提供できるように、ラインスプリッタが必要でした。
注:このアプローチのクレジットは、私が彼の許可なく公然と名を挙げない別の開発者になります。私がしたことは完全なパーサからラインスプリッタにそれを適用することでした。
更新:前lineSplitter実装において、いくつかの壊れたエッジケースを発見し
。提供されるものは、完全にRFC 4180に準拠する必要があります。
あなたは、単にこの使用して正規表現を行うことはできません。あなたは、いくつかの、あるいはほとんどの条件を扱う正規表現を作成することができます。しかし、正規表現では動作しない有効なCSVが常に存在します。 –
正規表現は解析用であり、解析用ではありません。テキストをスキャンするときに、文字以外のもの(つまり、引用されたリテラルの「内側」)を「記憶」する必要がある場合は、その文字を解析しています。微妙な違いは、誰もがそれを解析するために使用したい理由です。 –