NodeJS Javascript中的CSV分隔符自动检测

5jvtdoz2  于 2022-11-03  发布在  Node.js
关注(0)|答案(4)|浏览(259)

如何从Javascript/NodeJS中的字符串中检测CSV分隔符?
哪一个是标准算法?
请注意,分隔符并不总是逗号。最常见的分隔符是;,\t(制表符)。

6vl6ewon

6vl6ewon1#

获取可能的分隔符的可能算法非常简单,并且假设数据是格式良好的:
1.对于每个分隔符,
1.对于每一行,
1.按分隔符拆分行,检查length
1.如果它的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不会只返回整行,注意,它返回了一个可能的分隔符数组--如果有多个项,就会有歧义问题。

jmp7cifd

jmp7cifd2#

另一个解决方案是使用csv字符串包中的detect方法:
检测(输入:String):String检测最佳分隔符。

var CSV = require('csv-string');

    console.log(CSV.detect('a,b,c')); // OUTPUT : ","
    console.log(CSV.detect('a;b;c')); // OUTPUT : ";"
    console.log(CSV.detect('a|b|c')); // OUTPUT : "|"
    console.log(CSV.detect('a\tb\tc'));// OUTPUT : "\t"
rdrgkggo

rdrgkggo3#

此解决方案允许仅检测顶部行的csv分隔符,并通过使用csv-parse处理引用字段。
对于大型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);
        });
    });
}
s3fp2yjn

s3fp2yjn4#

function delimiter(csvText) {
    t = t.split("\n")[0];
    let delArray = [',', ';', '|', '    '];
    let comma = samiclon = pipe = tab = 0;
    delArray.forEach((e, i) => {
        if (i === 0) {
            comma = t.split(e).length;
        } else if (i === 1) {
            samiclon = t.split(e).length;
        } else if (i === 2) {
            pipe = t.split(e).length;
        } else if (i === 3) {
            tab = t.split(e).length;
        }
    });
    let tmpArray1 = [comma, samiclon, pipe, tab]
    let tmpArray = [comma, samiclon, pipe, tab];
    let maxLen = tmpArray.sort((a, b) => b - a)[0];
    let delimiter_i = 0;
    tmpArray1.forEach((e, i) => {
        if (maxLen === e) {
            delimiter_i = i;
        }
    });
    if (delimiter_i === 0) {
        return ',';
    } else if (delimiter_i === 1) {
        return ';'
    } else if (delimiter_i === 2) {
        return '|'
    } else if (delimiter_i === 3) {
        return '    '
    }
}

相关问题