8

Javascript/NodeJS の文字列から CSV セパレータを検出するにはどうすればよいですか?

標準アルゴリズムはどれですか?

セパレータは常にコンマではないことに注意してください。最も一般的な区切り記号は;,および\t(タブ) です。

4

3 に答える 3

20

可能性のあるセパレーターを取得するための可能なアルゴリズムは非常に単純で、データが整形式であることを前提としています。

  1. 区切り文字ごとに、
    1. ラインごとに、
      1. 区切り文字で行を分割し、 を確認しlengthます。
      2. 最後の行の長さと等しくない場合、これlengthは有効な区切り文字ではありません。

概念実証 (引用されたフィールドを処理しません):

function guessDelimiters (text, possibleDelimiters) {
    return possibleDelimiters.filter(weedOut);

    function weedOut (delimiter) {
        var cache = -1;
        return text.split('\n').every(checkLength);

        function checkLength (line) {
            if (!line) {
                return true;
            }

            var length = line.split(delimiter).length;
            if (cache < 0) {
                cache = length;
            }
            return cache === length && length > 1;
        }
    }
}

length > 1チェックは、行全体が返されなかったことを確認することですsplit。これは可能な区切り文字の配列を返すことに注意してください - 複数の項目がある場合、あいまいさの問題があります。

于 2013-09-28T18:26:25.087 に答える
0

このソリューションでは、 csv-parseを使用して、先頭行のみの csv セパレーターを検出し、引用符で囲まれたフィールドを処理できます。

大きな csv ファイルでは、ファイル全体を何度も読み取るのを避けるのに役立ちます。

const parse = require('csv-parse/lib/sync');
const fs = require('fs')

function detectCsvDelimiter(file, maxLineCount, delimiters = [',', ';', '\t']) {
    return new Promise((resolve, reject) => {
        // Read only maxLineCount lines
        let stream = fs.createReadStream(file, { 
                 flags: 'r', encoding: 'utf-8', bufferSize: 64 * 1024 });
        let lineCounter = 0;
        let data = '';
        stream.on("data", (moreData) => {
            data += moreData;
            lineCounter += data.split("\n").length - 1;
            if (lineCounter > maxLineCount + 1) {
                stream.destroy();
                // Remove invalid last line
                resolve(data.split('\n').slice(0, maxLineCount));
            }
        });
        stream.on("error", (err) => reject(err));
        stream.on("end", () => resolve(data.split("\n")));
    }).then(lines => {
        return new Promise(resolve => {
            const csvData = lines.join("\n");
            const validDelimiters = delimiters.filter(delimiter => {
                let isValid = true;
                // csv-parse throw error by default 
                // if the number of columns is inconsistent between lines
                try {
                    const rows = parse(csvData, {delimiter});
                    isValid = rows.some(row => row.length > 1);
                } catch (e) {
                    isValid = false;
                }
                return isValid;
            });
            resolve(validDelimiters);
        });
    });
}
于 2019-06-04T15:48:51.603 に答える