データにカンマが含まれるJavaScriptでCSV文字列を解析するにはどうすればよいですか?


93

次のタイプの文字列があります

var string = "'string, duppi, du', 23, lala"

文字列をカンマごとに配列に分割しますが、単一引用符の外側のカンマのみです。

私は分割の正しい正規表現を理解できません...

string.split(/,/)

くれます

["'string", " duppi", " du'", " 23", " lala"]

しかし、結果は次のようになります。

["string, duppi, du", "23", "lala"]

クロスブラウザソリューションはありますか?


常に単一引用符ですか?引用符で囲まれた文字列内に単一引用符があることはありますか?もしそうなら、それはどのようにエスケープされますか(バックスラッシュ、ダブルアップ)?
Phrogz

JavaScriptとHTML / XMLコードのように、引用符が二重引用符と単一引用符の間で完全に交換可能な場合はどうなりますか?もしそうなら、これはCSVよりも広範な解析操作を必要とします。
オースティンチェニー

実際にはそうです。バックスラッシュでエスケープしても問題ありません。
ハンス

値を二重引用符で囲んだ文字列にすることはできますか?
ridgerunner

1
パパパースは素晴らしい仕事をします。JavaScriptとパパ解析とローカルCSVファイルの解析:joyofdata.de/blog/...
ラファエル

回答:


214

免責事項

2014-12-01更新:以下の回答は、CSVの非常に具体的な1つの形式に対してのみ機能します。コメントでDGが正しく指摘しているように、このソリューションは、CSVのRFC 4180定義に適合せず、MS Excel形式にも適合しません。このソリューションは、文字列タイプの混合を含む入力の1つの(非標準)CSV行を解析する方法を単に示しています。ここで、文字列はエスケープされた引用符とコンマを含む場合があります。

非標準のCSVソリューション

austincheneyが正しく指摘しているように、エスケープ文字を含む可能性のある引用符付き文字列を適切に処理したい場合は、文字列を最初から最後まで解析する必要があります。また、OPは「CSV文字列」が実際に何であるかを明確に定義していません。最初に、有効なCSV文字列の構成要素とその個々の値を定義する必要があります。

指定:「CSV文字列」の定義

この説明では、「CSV文字列」は0個以上の値で構成され、複数の値はコンマで区切られています。各値は次のもので構成されます。

  1. 二重引用符で囲まれた文字列。(エスケープされていない単一引用符が含まれる場合があります。)
  2. 一重引用符で囲まれた文字列。(エスケープされていない二重引用符が含まれる場合があります。)
  3. 引用符で囲まれていない文字列。(引用符、カンマ、バックスラッシュを含めることはできません。)
  4. 空の値。(すべて空白の値は空と見なされます。)

ルール/メモ:

  • 引用符で囲まれた値にはカンマが含まれる場合があります。
  • 引用符で囲まれた値には、エスケープされたすべてのものを含めることができます'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:免責事項を先頭に移動しました。


1
@Evan Plaice-素敵な言葉をありがとう。もちろん、任意のセパレータを使用できます。正規表現内のすべてのコンマを選択したセパレーターに置き換えるだけです(ただし、セパレーターを空白にすることはできません)。乾杯。
ridgerunner 2012

2
@Evan Plaice-あなたはあなたが望むどんな目的のために私の正規表現のどれを使っても大丈夫です。認識のメモはいいですが、必要ではありません。プラグインで頑張ってください。乾杯!
ridgerunner 2012

1
クール、これがプロジェクトcode.google.com/p/jquery-csvです。最終的に、SSV(Structured Separated Values)と呼ばれるCSVに拡張形式を追加します。これは、メタデータ(つまり、区切り文字、セパレーター、行末など)が含まれた単なるCSVです。
Evan Plaice

1
このすばらしい実装に感謝します-私はそれをNode.jsモジュール(csv-iterator)のベースとして使用しました。
ミルコキーファー

3
私は詳細を賞賛し、あなたの答えを明確にしますが、CSVの定義がRFC 4180に適合しないことをどこかに指摘する必要があります。特に、これは文字列フィールド内の二重引用符文字を「エスケープ」する通常の方法です。"field one", "field two", "a ""final"" field containing two double quote marks"このページではTrevor Dixonの回答をテストしていませんが、これはCSVのRFC 4180定義に対処する回答です。
DG。

53

RFC 4180ソリューション

形式はRFC 4180に準拠していないため、これは問題の文字列を解決しません。許容されるエンコードは、二重引用符で二重引用符をエスケープしています。以下のソリューションは、GoogleスプレッドシートのCSVファイルで正しく機能します。

アップデート(2017年3月)

単一行の解析は間違っているでしょう。RFC 4180によると、フィールドにはCRLFが含まれている可能性があり、これによりラインリーダーがCSVファイルを破壊します。以下は、CSV文字列を解析する更新バージョンです。

'use strict';

function csvToArray(text) {
    let p = '', row = [''], ret = [row], i = 0, r = 0, s = !0, l;
    for (l of text) {
        if ('"' === l) {
            if (s && l === p) row[i] += l;
            s = !s;
        } else if (',' === l && s) l = row[++i] = '';
        else if ('\n' === l && s) {
            if ('\r' === p) row[i] = row[i].slice(0, -1);
            row = ret[++r] = [l = '']; i = 0;
        } else row[i] += l;
        p = l;
    }
    return ret;
};

let test = '"one","two with escaped """" double quotes""","three, with, commas",four with no quotes,"five with CRLF\r\n"\r\n"2nd line one","two with escaped """" double quotes""","three, with, commas",four with no quotes,"five with CRLF\r\n"';
console.log(csvToArray(test));

古い答え

(単一行ソリューション)

function CSVtoArray(text) {
    let ret = [''], i = 0, p = '', s = true;
    for (let l in text) {
        l = text[l];
        if ('"' === l) {
            s = !s;
            if ('"' === p) {
                ret[i] += '"';
                l = '-';
            } else if ('' === p)
                l = '-';
        } else if (s && ',' === l)
            l = ret[++i] = '';
        else
            ret[i] += l;
        p = l;
    }
    return ret;
}
let test = '"one","two with escaped """" double quotes""","three, with, commas",four with no quotes,five for fun';
console.log(CSVtoArray(test));

楽しみのために、配列からCSVを作成する方法を次に示します。

function arrayToCSV(row) {
    for (let i in row) {
        row[i] = row[i].replace(/"/g, '""');
    }
    return '"' + row.join('","') + '"';
}

let row = [
  "one",
  "two with escaped \" double quote",
  "three, with, commas",
  "four with no quotes (now has)",
  "five for fun"
];
let text = arrayToCSV(row);
console.log(text);


1
これは私のために仕事をしました、他のものはしませんでした
WtFudgE

7

http://en.wikipedia.org/wiki/Comma-separated_valuesで RFC 4180の例を処理するPEG(.js)文法:

start
  = [\n\r]* first:line rest:([\n\r]+ data:line { return data; })* [\n\r]* { rest.unshift(first); return rest; }

line
  = first:field rest:("," text:field { return text; })*
    & { return !!first || rest.length; } // ignore blank lines
    { rest.unshift(first); return rest; }

field
  = '"' text:char* '"' { return text.join(''); }
  / text:[^\n\r,]* { return text.join(''); }

char
  = '"' '"' { return '"'; }
  / [^"]

http://jsfiddle.net/knvzk/10またはhttps://pegjs.org/onlineでテストします

生成されたパーサーをhttps://gist.github.com/3362830からダウンロードします


6

Googleスプレッドシートから自分のウェブアプリにセルをコピーしたいという非常に特殊なユースケースがありました。セルには、二重引用符と改行文字を含めることができます。コピーアンドペーストを使用すると、セルはタブ文字で区切られ、奇数のデータを持つセルは二重引用符で囲まれます。この主なソリューションである、regexpを使用したリンクされた記事、Jquery-CSV、およびCSVToArrayを試しました。 http://papaparse.com/ すぐに使える唯一の製品です。コピーと貼り付けは、デフォルトの自動検出オプションを備えたGoogleスプレッドシートとシームレスです。


1
これははるかに上位にランク付けする必要があります。独自のCSVパーサーをロールバックしようとしないでください。特に、正規表現を使用する場合は正しく機能しません。Papaparseは素晴らしい -使ってみよう!
cbley 2017

6

私はFakeRainBrigandの答えが好きでしたが、いくつかの問題が含まれています:引用符とカンマの間の空白を処理できず、2つの連続するカンマをサポートしていません。私は彼の回答を編集しようとしましたが、私の編集はどうやら私のコードを理解していないレビューアによって拒否されました。これが私のバージョンのFakeRainBrigandのコードです。フィドルもあります:http : //jsfiddle.net/xTezm/46/

String.prototype.splitCSV = function() {
        var matches = this.match(/(\s*"[^"]+"\s*|\s*[^,]+|,)(?=,|$)/g);
        for (var n = 0; n < matches.length; ++n) {
            matches[n] = matches[n].trim();
            if (matches[n] == ',') matches[n] = '';
        }
        if (this[0] == ',') matches.unshift("");
        return matches;
}

var string = ',"string, duppi, du" , 23 ,,, "string, duppi, du",dup,"", , lala';
var parsed = string.splitCSV();
alert(parsed.join('|'));

4

人々はこれについてRegExに反対しているようでした。どうして?

(\s*'[^']+'|\s*[^,]+)(?=,|$)

これがコードです。フィドルも作りました。

String.prototype.splitCSV = function(sep) {
  var regex = /(\s*'[^']+'|\s*[^,]+)(?=,|$)/g;
  return matches = this.match(regex);    
}

var string = "'string, duppi, du', 23, 'string, duppi, du', lala";
var parsed = string.splitCSV();
alert(parsed.join('|'));

3
ふむ、正規表現にはいくつかの問題があります。引用符とカンマの間の空白を処理できず、2つの連続するカンマをサポートしていません。両方の問題を修正するコードで回答を更新し、新しいフィドルを作成しました:jsfiddle.net/xTezm/43
HammerNL

なんらかの理由で、コードの編集は「投稿の元の意図から逸脱する」ために拒否されました。非常に奇妙な!?私はあなたのコードを取り、それに関する2つの問題を修正しました。それは投稿の意図をどのように変えますか?とにかく...この質問に新しい回答を追加しました。
HammerNL 2016年

@FakeRainBrigand、あなたの答えに良い質問があります。私はすべて正規表現に賛成です。それが原因で、それがこの仕事には不適切なツールであることを認めます。
niry 2017年

2
@niryここの私のコードはひどいです。私は過去6年間で良くなったと約束します:-p
Brigand

4

上記のすべてを十分に「KISS」ではないため、リストにもう1つ追加します。

これは正規表現を使用して、引用された項目をスキップしながら、コンマまたは改行を検索します。うまくいけば、これは初心者が自分で読むことができるものです。splitFinder正規表現は、それが(Aによるスプリットない3つのことを持っています|):

  1. , -カンマを検索します
  2. \r?\n -新しい行を見つけます(エクスポーターが良かった場合は、キャリッジリターンで潜在的に)。
  3. "(\\"|[^"])*?"-引用符で囲まれたものはすべてスキップします。カンマや改行はそこでは関係ないためです。\\"引用されたアイテムにエスケープされた引用がある場合、終了引用が見つかる前にキャプチャされます。

const splitFinder = /,|\r?\n|"(\\"|[^"])*?"/g;

function csvTo2dArray(parseMe) {
  let currentRow = [];
  const rowsOut = [currentRow];
  let lastIndex = splitFinder.lastIndex = 0;
  
  // add text from lastIndex to before a found newline or comma
  const pushCell = (endIndex) => {
    endIndex = endIndex || parseMe.length;
    const addMe = parseMe.substring(lastIndex, endIndex);
    // remove quotes around the item
    currentRow.push(addMe.replace(/^"|"$/g, ""));
    lastIndex = splitFinder.lastIndex;
  }


  let regexResp;
  // for each regexp match (either comma, newline, or quoted item)
  while (regexResp = splitFinder.exec(parseMe)) {
    const split = regexResp[0];

    // if it's not a quote capture, add an item to the current row
    // (quote captures will be pushed by the newline or comma following)
    if (split.startsWith(`"`) === false) {
      const splitStartIndex = splitFinder.lastIndex - split.length;
      pushCell(splitStartIndex);

      // then start a new row if newline
      const isNewLine = /^\r?\n$/.test(split);
      if (isNewLine) { rowsOut.push(currentRow = []); }
    }
  }
  // make sure to add the trailing text (no commas or newlines after)
  pushCell();
  return rowsOut;
}

const rawCsv = `a,b,c\n"test\r\n","comma, test","\r\n",",",\nsecond,row,ends,with,empty\n"quote\"test"`
const rows = csvTo2dArray(rawCsv);
console.log(rows);


fileReaderを使用してファイルを読み取り、その結果:Id, Name, Age 1, John Smith, 65 2, Jane Doe, 30 指定した列に基づいて解析するにはどうすればよいですか?
bluePearl

2D配列を取得したら、最初のインデックス(プロップ名)を削除し、残りの配列を反復処理して、各値をプロパティとしてオブジェクトを作成します。:それはこのようになります[{Id: 1, Name: "John Smith", Age: 65}, {Id: 2, Name: "Jane Doe", Age: 30}]
SEPHリード

3

引用符区切り文字を二重引用符で囲むことができる場合、これはCSVデータを解析するJavaScriptコードの複製です。

最初にすべての単一引用符を二重引用符に変換することもできます。

string = string.replace( /'/g, '"' );

...または、その質問の正規表現を編集して、二重引用符の代わりに単一引用符を認識することができます。

// Quoted fields.
"(?:'([^']*(?:''[^']*)*)'|" +

ただし、これはあなたの質問から明らかではない特定のマークアップを想定しています。質問に対する私のコメントに従って、マークアップのさまざまな可能性をすべて明確にしてください。


2

私の回答は、入力が、エスケープされていない一致セットとして発生する場合、一重引用符と二重引用符が完全に交換可能なWebソースからのコード/コンテンツを反映していると想定しています。

これには正規表現を使用できません。実際には、分割したい文字列を分析するためのマイクロパーサーを作成する必要があります。この回答のために、文字列の引用部分をサブ文字列と呼びます。具体的には、文字列を横切る必要があります。次のケースを考えてみましょう:

var a = "some sample string with \"double quotes\" and 'single quotes' and some craziness like this: \\\" or \\'",
    b = "sample of code from JavaScript with a regex containing a comma /\,/ that should probably be ignored.";

この場合、文字パターンの入力を分析するだけで、部分文字列がどこで開始または終了するかはまったくわかりません。代わりに、引用文字が引用文字として使用され、それ自体が引用符で囲まれておらず、引用文字がエスケープに従っていないかどうかを判断するロジックを記述する必要があります。

そのレベルのコードの複雑さを書くつもりはありませんが、私が最近書いた、必要なパターンがあるものを見ることができます。このコードはコンマとは何の関係もありませんが、それ以外の点では、独自のコードを記述する際にフォローできる十分な有効なマイクロパーサーです。次のアプリケーションのasifix関数を調べます。

https://github.com/austincheney/Pretty-Diff/blob/master/fulljsmin.js


2

csvを文字列に読み込んでいるときに、文字列の間にnull値が含まれているため、\ 0行ごとに試してみてください。

stringLine = stringLine.replace( /\0/g, "" );

2

この答えを補足する

別の引用符でエスケープされた引用符を解析する必要がある場合、例:

"some ""value"" that is on xlsx file",123

使用できます

function parse(text) {
  const csvExp = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|"([^""]*(?:"[\S\s][^""]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;

  const values = [];

  text.replace(csvExp, (m0, m1, m2, m3, m4) => {
    if (m1 !== undefined) {
      values.push(m1.replace(/\\'/g, "'"));
    }
    else if (m2 !== undefined) {
      values.push(m2.replace(/\\"/g, '"'));
    }
    else if (m3 !== undefined) {
      values.push(m3.replace(/""/g, '"'));
    }
    else if (m4 !== undefined) {
      values.push(m4);
    }
    return '';
  });

  if (/,\s*$/.test(text)) {
    values.push('');
  }

  return values;
}

これはまだ解析に失敗していることがわかりました"jjj "" kkk""","123"
niry

2

CSVファイルを解析する必要があるときにも、同じタイプの問題に直面しました。ファイルには、「、」を含むアドレス列が含まれています。
そのCSVをJSONに解析した後、JSONファイルに変換するときにキーのマッピングが一致しなくなります。 baby parsecsvtojson
などのファイルとライブラリの解析にノードを使用しましたファイルの 例-

address,pincode
foo,baar , 123456

JSONでbaby parseを使用せずに直接解析しているときに、

[{
 address: 'foo',
 pincode: 'baar',
 'field3': '123456'
}]

だから私はすべてのフィールドで他のデリミタでコンマ(、)を削除するコードを書きました

/*
 csvString(input) = "address, pincode\\nfoo, bar, 123456\\n"
 output = "address, pincode\\nfoo {YOUR DELIMITER} bar, 123455\\n"
*/
const removeComma = function(csvString){
    let delimiter = '|'
    let Baby = require('babyparse')
    let arrRow = Baby.parse(csvString).data;
    /*
      arrRow = [ 
      [ 'address', 'pincode' ],
      [ 'foo, bar', '123456']
      ]
    */
    return arrRow.map((singleRow, index) => {
        //the data will include 
        /* 
        singleRow = [ 'address', 'pincode' ]
        */
        return singleRow.map(singleField => {
            //for removing the comma in the feild
            return singleField.split(',').join(delimiter)
        })
    }).reduce((acc, value, key) => {
        acc = acc +(Array.isArray(value) ?
         value.reduce((acc1, val)=> {
            acc1 = acc1+ val + ','
            return acc1
        }, '') : '') + '\n';
        return acc;
    },'')
}

返された関数はcsvtojsonライブラリに渡すことができるため、結果を使用できます。

const csv = require('csvtojson')

let csvString = "address, pincode\\nfoo, bar, 123456\\n"
let jsonArray = []
modifiedCsvString = removeComma(csvString)
csv()
  .fromString(modifiedCsvString)
  .on('json', json => jsonArray.push(json))
  .on('end', () => {
    /* do any thing with the json Array */
  })
今、あなたは次のような出力を得ることができます

[{
  address: 'foo, bar',
  pincode: 123456
}]

2

https://en.wikipedia.org/wiki/Comma-separated_values#Basic_rulesによると、正規表現なし、読み取り可能

function csv2arr(str: string) {
    let line = ["",];
    const ret = [line,];
    let quote = false;

    for (let i = 0; i < str.length; i++) {
        const cur = str[i];
        const next = str[i + 1];

        if (!quote) {
            const cellIsEmpty = line[line.length - 1].length === 0;
            if (cur === '"' && cellIsEmpty) quote = true;
            else if (cur === ",") line.push("");
            else if (cur === "\r" && next === "\n") { line = ["",]; ret.push(line); i++; }
            else if (cur === "\n" || cur === "\r") { line = ["",]; ret.push(line); }
            else line[line.length - 1] += cur;
        } else {
            if (cur === '"' && next === '"') { line[line.length - 1] += cur; i++; }
            else if (cur === '"') quote = false;
            else line[line.length - 1] += cur;
        }
    }
    return ret;
}

1

このブログ投稿によると、この関数はそれを行うべきです:

String.prototype.splitCSV = function(sep) {
  for (var foo = this.split(sep = sep || ","), x = foo.length - 1, tl; x >= 0; x--) {
    if (foo[x].replace(/'\s+$/, "'").charAt(foo[x].length - 1) == "'") {
      if ((tl = foo[x].replace(/^\s+'/, "'")).length > 1 && tl.charAt(0) == "'") {
        foo[x] = foo[x].replace(/^\s*'|'\s*$/g, '').replace(/''/g, "'");
      } else if (x) {
        foo.splice(x - 1, 2, [foo[x - 1], foo[x]].join(sep));
      } else foo = foo.shift().split(sep).concat(foo);
    } else foo[x].replace(/''/g, "'");
  } return foo;
};

次のように呼び出します。

var string = "'string, duppi, du', 23, lala";
var parsed = string.splitCSV();
alert(parsed.join("|"));

このjsfiddleは機能しますが、一部の要素の前にスペースがあるようです。


これらすべてを正規表現で行う必要があると想像してください。これが、正規表現が解析に適さない場合がある理由です。
CanSpice

このソリューションは単に機能しません。:元のテスト文字列を考える"'string, duppi, du', 23, lala":この関数が戻っ["'string"," duppi"," du'"," 23"," lala"]
ridgerunner

@ridgerunner:そうです。関数を修正するために、答えとjsfiddleを編集しました。基本的に、私はその逆に切り替え"'"ました'"'
CanSpice

これは役に立ちましたが、今では、関数は二重引用符で囲まれた値を持つ単一引用符で囲まれたCSV文字列を誤って処理します。例えばそのようなオリジナルのテスト文字列の引用符の種類反転:'"string, duppi, du", 23, lala'で結果:['"string',' duppi'.' du"',' 23',' lala']
ridgerunner

@CanSpice、あなたのコメントはRegExで試すように私に影響を与えました。それほど多くの機能はありませんが、簡単に追加できます。(興味がある場合、私の答えはこのページにあります。)
Brigand

0

ridgerunnerからの優れた完全な回答の他に、バックエンドがphpを実行するときの非常に簡単な回避策を考えました。

(言う:ドメインのバックエンドに、このPHPファイルを追加しますcsv.php

<?php
session_start(); //optional
header("content-type: text/xml");
header("charset=UTF-8");
//set the delimiter and the End of Line character of your csv content:
echo json_encode(array_map('str_getcsv',str_getcsv($_POST["csv"],"\n")));
?>

次に、この関数をJavaScriptツールキットに追加します(クロスブラウザーを作成するために少し修正する必要があります)。

function csvToArray(csv) {
    var oXhr = new XMLHttpRequest;
    oXhr.addEventListener("readystatechange",
            function () {
                if (this.readyState == 4 && this.status == 200) {
                    console.log(this.responseText);
                    console.log(JSON.parse(this.responseText));
                }
            }
    );
    oXhr.open("POST","path/to/csv.php",true);
    oXhr.setRequestHeader("Content-type","application/x-www-form-urlencoded; charset=utf-8");
    oXhr.send("csv=" + encodeURIComponent(csv));
}

ajax呼び出しは1回かかりますが、少なくともコードを複製したり、外部ライブラリを含めたりすることはありません。

参照:http : //php.net/manual/en/function.str-getcsv.php


0

以下の例のようにpapaparse.jsを使用できます。

<!DOCTYPE html>
<html lang="en">
<head>
    <title>CSV</title>
</head>
<body>

    <input type="file" id="files" multiple="">
    <button onclick="csvGetter()">CSV Getter</button>
    <h3>The Result will be in the Console.</h3>


<script src="papaparse.min.js"></script>
<script>
     function csvGetter() {

        var file = document.getElementById('files').files[0];
        Papa.parse(file, {
            complete: function(results) {
                console.log(results.data);
                }
           });
        }

  </script>

同じフォルダーにpapaparse.jsを含めることを忘れないでください。


0

救助への正規表現!これらの数行のコードは、RFC 4180標準に基づいて、コンマ、引用符、および改行が埋め込まれた適切に引用されたフィールドを処理します。

function parseCsv(data, fieldSep, newLine) {
    fieldSep = fieldSep || ',';
    newLine = newLine || '\n';
    var nSep = '\x1D';
    var qSep = '\x1E';
    var cSep = '\x1F';
    var nSepRe = new RegExp(nSep, 'g');
    var qSepRe = new RegExp(qSep, 'g');
    var cSepRe = new RegExp(cSep, 'g');
    var fieldRe = new RegExp('(?<=(^|[' + fieldSep + '\\n]))"(|[\\s\\S]+?(?<![^"]"))"(?=($|[' + fieldSep + '\\n]))', 'g');
    var grid = [];
    data.replace(/\r/g, '').replace(/\n+$/, '').replace(fieldRe, function(match, p1, p2) {
        return p2.replace(/\n/g, nSep).replace(/""/g, qSep).replace(/,/g, cSep);
    }).split(/\n/).forEach(function(line) {
        var row = line.split(fieldSep).map(function(cell) {
            return cell.replace(nSepRe, newLine).replace(qSepRe, '"').replace(cSepRe, ',');
        });
        grid.push(row);
    });
    return grid;
}

const csv = 'A1,B1,C1\n"A ""2""","B, 2","C\n2"';
const separator = ',';      // field separator, default: ','
const newline = ' <br /> '; // newline representation in case a field contains newlines, default: '\n' 
var grid = parseCsv(csv, separator, newline);
// expected: [ [ 'A1', 'B1', 'C1' ], [ 'A "2"', 'B, 2', 'C <br /> 2' ] ]

他に記載がない限り、有限状態機械は必要ありません。正規表現は、肯定的な後読み、否定的な後読み、および肯定的な先読みにより、RFC 4180を適切に処理します。

https://github.com/peterthoeny/parse-csv-jsでコードを複製/ダウンロード

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.