如何从Javascript/NodeJS中的字符串中检测CSV分隔符?哪一个是标准算法?请注意,分隔符并不总是逗号。最常见的分隔符是;、,和\t(制表符)。
;
,
\t
6vl6ewon1#
获取可能的分隔符的可能算法非常简单,并且假设数据是格式良好的:1.对于每个分隔符,1.对于每一行,1.按分隔符拆分行,检查length。1.如果它的length * 不 * 等于最后一行的长度,则这不是有效的分隔符。概念验证(不处理带引号的字段):
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不会只返回整行,注意,它返回了一个可能的分隔符数组--如果有多个项,就会有歧义问题。
length > 1
split
jmp7cifd2#
另一个解决方案是使用csv字符串包中的detect方法:检测(输入:String):String检测最佳分隔符。
detect
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"
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); }); }); }
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 ' ' } }
4条答案
按热度按时间6vl6ewon1#
获取可能的分隔符的可能算法非常简单,并且假设数据是格式良好的:
1.对于每个分隔符,
1.对于每一行,
1.按分隔符拆分行,检查
length
。1.如果它的
length
* 不 * 等于最后一行的长度,则这不是有效的分隔符。概念验证(不处理带引号的字段):
length > 1
检查是为了确保split
不会只返回整行,注意,它返回了一个可能的分隔符数组--如果有多个项,就会有歧义问题。jmp7cifd2#
另一个解决方案是使用csv字符串包中的
detect
方法:检测(输入:String):String检测最佳分隔符。
rdrgkggo3#
此解决方案允许仅检测顶部行的csv分隔符,并通过使用csv-parse处理引用字段。
对于大型csv文件,它可以避免多次阅读整个文件。
s3fp2yjn4#