我在CSV文件上摸不着头脑,由于很多错误,我无法正确解析。我提取了一个样本,您可以在此处下载:Test CSV File
主要错误(或产生错误的原因)是:
我首先决定逐行使用正则表达式来清理数据,然后再将它们加载到R中,但无法解决问题,这是两个慢(200Mo文件)
所以我决定在Node.js下使用CSV parser,代码如下:
'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)
可是:
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);
编辑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);
感谢大家!
答案 0 :(得分:1)
数据并不太混乱。有一个明确的模式。
一般步骤:
上面的第1步是最重要的。如果你应用它,那么新行,空行,引号和逗号的问题就会消失。如果查看数据,可以看到第7,8和9列包含混合数据。但始终以2引号或更多分隔。 e.g。
good,clean,data,here,"""<-BEGINNING OF FIELD DATA> Oh no
++\n\n<br/>whats happening,, in here, pages of chinese
characters etc END OF FIELD ->""",more,clean,data
以下是基于提供的文件的工作示例:
fs.readFile('./data_stack.csv', (e, data) => {
// Take out fields that are delimited with double+ quotes
var dirty = data.toString();
var matches = dirty.match(/""[\s\S]*?""/g);
matches.forEach((m,i) => {
dirty = dirty.replace(m, "<REPL-" + i + ">");
});
var cleanData = dirty
.split('\n') // get lines
// ignore first line with column names
.filter((l, i) => i > 0)
// remove first and last quotation mark if exists
.map(l => l[0] === '"' ? l.substring(1, l.length-2) : l) // remove quotes from quoted lines
// split into columns
.map(l => l.split(','))
// return replaced fields back to data (columsn 7,8 and 9)
.map(col => {
if (col.length > 9) {
col[7] = returnField(col[7]);
col[8] = returnField(col[8]);
col[9] = returnField(col[9]);
}
return col;
function returnField(f) {
if (f) {
var repls = f.match(/<.*?>/g)
if (repls)
repls.forEach(m => {
var num = +m.split('-')[1].split('>')[0];
f = f.replace(m, matches[num]);
});
}
return f;
}
})
return cleanData
});
数据看起来很干净。所有行都产生与标题匹配的预期列数(显示的最后2行):
...,
[ '19403',
'560e348d2adaffa66f72bfc9',
'done',
'276',
'2015-10-02T07:38:53.172Z',
'20151002',
'560e31f69cd6d5059668ee16',
'""560e336ef3214201030bf7b5""',
'a+�a��a+�a+�a��a+�a��a+�a��',
'',
'560e2e362adaffa66f72bd99',
'55f8f041b971644d7d861502',
'foo',
'foo',
'foo@bar.com',
'bar.com' ],
[ '20388',
'560ce1a467cf15ab2cf03482',
'update',
'231',
'2015-10-01T07:32:52.077Z',
'20151001',
'560ce1387494620118c1617a',
'""""""Final test, with a comma""""""',
'',
'',
'55e6dff9b45b14570417a908',
'55e6e00fb45b14570417a92f',
'foo',
'foo',
'foo@bar.com',
'bar.com' ],
答案 1 :(得分:1)
我不知道如何使这个CSV干净,既不用R也不用 Node.js的。
实际上,它并没有看起来那么糟糕。
使用以下步骤可以轻松地将此文件转换为有效的csv:
""
替换为"
。\n"
替换为\n
。"\n
替换为\n
。 \n
表示换行符,而不是字符&#34; \n
&#34;它也出现在你的文件中。
请注意,在您的示例文件中,\n
实际上是\r\n
(0x0d
,0x0a
),因此根据您使用的软件,您可能需要替换{{1在上面示例中的\n
中。此外,在您的示例中,在最后一行之后有一个换行符,因此作为最后一个字符的引号也将被替换,但您可能希望在原始文件中检查它。
这应该产生一个有效的csv文件:
仍然会有多行字段,但这可能是有意的。但现在这些都被正确引用,任何体面的csv解析器都应该能够处理多行字段。
看起来原始数据有一个额外的传递来转义引号字符:
如果原始字段包含\r\n
,则会引用它们,如果这些字段已包含引号,则引号会使用其他引号进行转义 - 这是正确的方法。
但是所有包含引号的行似乎都被引用了(实际上将这些行转换为一个引用的字段),并且该行中的所有引号都使用另一个引号进行了转义。
显然,多行字段出了问题。在多行之间也添加了引号,这不是正确的方法。
答案 2 :(得分:0)
继续发表评论:
数据太乱了,无法一步到位,不要尝试。
首先确定双引号和/或逗号是否可能是数据的一部分。如果不是,请使用简单的正则表达式删除双引号。
接下来,每行应该有14个逗号。将文件作为文本读取,并依次计算每行的逗号数。如果小于14,请检查以下行,如果逗号之和为14,则合并2行。如果总和小于14,请检查下一行并继续,直到您有14个逗号。如果下一行超过14,则会出现严重错误,请记下行号 - 您可能需要手动修复。保存生成的文件。
幸运的是,您现在将拥有一个可以作为CSV处理的文件。如果没有,请返回部分整理的文件,我们可以尝试进一步提供帮助。
不用说你应该处理原件的副本,你不可能第一次就把它弄好:)