Javascript中CSV分隔符的自动检测

Javascript中CSV分隔符的自动检测,javascript,node.js,Javascript,Node.js,如何从Javascript/NodeJS中的字符串中检测CSV分隔符 哪个是标准算法 请注意,分隔符并不总是逗号。最常见的分隔符是、、和\t(选项卡)。获取可能的分隔符的可能算法非常简单,并且假设数据格式正确: 对于每个分隔符, 每行,, 按分隔符拆分行,检查长度 如果其长度不等于最后一行的长度,则该分隔符无效 概念证明(不处理引用字段): 函数猜测分隔符(文本、可能的限定符){ 返回可能的限制器。过滤器(weedOut); 函数weedOut(分隔符){ var cache=-1; 返回t

如何从Javascript/NodeJS中的字符串中检测CSV分隔符

哪个是标准算法


请注意,分隔符并不总是逗号。最常见的分隔符是
\t
(选项卡)。

获取可能的分隔符的可能算法非常简单,并且假设数据格式正确:

  • 对于每个分隔符,
  • 每行,,
  • 按分隔符拆分行,检查
    长度
  • 如果其
    长度
    不等于最后一行的长度,则该分隔符无效
  • 概念证明(不处理引用字段):

    函数猜测分隔符(文本、可能的限定符){
    返回可能的限制器。过滤器(weedOut);
    函数weedOut(分隔符){
    var cache=-1;
    返回text.split('\n').every(checkLength);
    函数校验长度(行){
    如果(!行){
    返回true;
    }
    var length=line.split(分隔符).length;
    if(缓存<0){
    缓存=长度;
    }
    返回缓存===length&&length>1;
    }
    }
    }
    

    length>1
    检查是为了确保
    split
    没有返回整行。请注意,这将返回一个可能的分隔符数组-如果有多个项,则表示存在歧义问题。

    另一种解决方案是使用包中的
    检测
    方法:

    检测(输入:字符串):字符串检测最佳分隔符


    此解决方案允许仅检测顶行的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);
            });
        });
    }
    

    Python是这样做的:您使用什么模块来解析CSV?@Blender最好将其移植到javascript中。我不是python专家。。。“我没有看到类似的问题。”约翰说ツ: 如果不使用命名组,它的注释很好,正则表达式应该可以正常工作。这就是一切。
        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"
    
    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);
            });
        });
    }