Javascript/NodeJS の文字列から CSV セパレータを検出するにはどうすればよいですか?
標準アルゴリズムはどれですか?
セパレータは常にコンマではないことに注意してください。最も一般的な区切り記号は;
、,
および\t
(タブ) です。
Javascript/NodeJS の文字列から CSV セパレータを検出するにはどうすればよいですか?
標準アルゴリズムはどれですか?
セパレータは常にコンマではないことに注意してください。最も一般的な区切り記号は;
、,
および\t
(タブ) です。
可能性のあるセパレーターを取得するための可能なアルゴリズムは非常に単純で、データが整形式であることを前提としています。
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
。これは可能な区切り文字の配列を返すことに注意してください - 複数の項目がある場合、あいまいさの問題があります。
このソリューションでは、 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);
});
});
}