如何用Node.js解析脏CSV?

Syn*_*leb 7 javascript csv parsing node.js

由于许多错误,我正在抓住我无法正确解析的CSV文件.我提取了一个可以在这里下载的样本:测试CSV文件

主要错误(或产生错误的原因)是:

  • 引号和逗号(尝试使用R解析文件时出现许多错误)
  • 空行
  • 字段内的意外换行

我首先决定逐行使用正则表达式来清理数据,然后将它们加载到R中,但无法解决问题,这是两个慢(200Mo文件)

所以我决定在Node.js下使用CSV解析器,代码如下:

'use strict';

const Fs  = require('fs');
const Csv = require('csv');

let input       = 'data_stack.csv';
let readStream  = Fs.createReadStream(input);
let option      = {delimiter: ',', quote: '"', escape: '"', relax: true};

let parser = Csv.parse(option).on('data', (data) => {
    console.log(data)
});

readStream.pipe(parser)
Run Code Online (Sandbox Code Playgroud)

但:

  • 正确解析了一些行(字符串数组)
  • 有些未解析(所有字段都是一个字符串)
  • 有些行仍然是空的(可以通过添加skip_empty_lines: true选项来解决)
  • 我不知道如何处理意外的换行符.

我不知道如何使这个CSV干净,无论是R还是Node.js.

有帮助吗?

编辑:

在@Danny_ds解决方案之后,我可以正确解析它.现在我无法正确地将其串回来.

与console.log();我得到一个合适的对象,但是当我试图字符串化它,我没有得到一个干净的CSV(仍然有断行和空行).

这是我正在使用的代码:

'use strict';

const Fs  = require('fs');
const Csv = require('csv');


let input  = 'data_stack.csv';
let output = 'data_output.csv';

let readStream  = Fs.createReadStream(input);
let writeStream = Fs.createWriteStream(output);

let opt  = {delimiter: ',', quote: '"', escape: '"', relax: true, skip_empty_lines: true};


let transformer = Csv.transform(data => {
    let dirty = data.toString();
    let replace = dirty.replace(/\r\n"/g, '\r\n').replace(/"\r\n/g, '\r\n').replace(/""/g, '"');

    return replace;
});

let parser = Csv.parse(opt);
let stringifier = Csv.stringify();

readStream.pipe(transformer).pipe(parser).pipe(stringifier).pipe(writeStream);
Run Code Online (Sandbox Code Playgroud)

编辑2:

这是最终的代码:

'use strict';

const Fs  = require('fs');
const Csv = require('csv');


let input  = 'data_stack.csv';
let output = 'data_output.csv';

let readStream  = Fs.createReadStream(input);
let writeStream = Fs.createWriteStream(output);

let opt  = {delimiter: ',', quote: '"', escape: '"', relax: true, skip_empty_lines: true};


let transformer = Csv.transform(data => {
    let dirty = data.toString();
    let replace = dirty
        .replace(/\r\n"/g, '\r\n')
        .replace(/"\r\n/g, '\r\n')
        .replace(/""/g, '"');

    return replace;
});

let parser = Csv.parse(opt);

let cleaner = Csv.transform(data => {
    let clean = data.map(l => {
        if (l.length > 100 || l[0] === '+') {
            return l = "Encoding issue";
        }
        return l;
    });
    return clean;
});

let stringifier = Csv.stringify();

readStream.pipe(transformer).pipe(parser).pipe(cleaner).pipe(stringifier).pipe(writeStream);
Run Code Online (Sandbox Code Playgroud)

谢谢大家!

Jul*_*ght 0

以下是我的评论:

数据太混乱,无法一步修复,请勿尝试。

首先确定双引号和/或逗号是否可能是数据的一部分。如果不是,请使用简单的正则表达式删除双引号。

接下来,每行应有 14 个逗号。将文件作为文本读取,并依次计算每行的逗号数量。如果少于 14 个,则检查以下行,如果逗号之和为 14,则合并 2 行。如果总和小于 14,请检查下一行并继续,直到有 14 个逗号为止。如果下一行超过 14,则存在严重错误,因此请记下行号 - 您可能需要手动修复。保存生成的文件。

幸运的是,您现在将拥有一个可以作为 CSV 进行处理的文件。如果没有,请返回部分整理的文件,我们可以尝试提供进一步的帮助。

不用说,您应该处理原件的副本,您不太可能第一次就做对:)