我有一个由MSExcel创建的CSV文件,其中包含元素内的随机回车。每行由最终CSV中的回车符分隔(我不知道它是否特定于MSExcel)。
假设我有10列和100行,最后一列的某些元素本身具有回车符(因此在最终输出中用双引号引用),有些则没有。
无论如何我可以正确分割这100行吗?
即使我已经准备好牺牲那些没有回车并且在最后手动添加一个,使所有10号,20号,30号元素以“+ \ n结束,JS似乎无法识别“\”\ n“作为有效的语法。
编辑:这种操作最好用php +数据库完成吗?如果是的话,我应该从哪里开始?
答案 0 :(得分:4)
如果您正在考虑使用.split()函数(对每个逗号进行简单拆分)来解析csv数据,那么您会以错误的方式思考它。典型的通用Split()函数对于csv是错误的,因为有各种边缘情况可以使它们绊倒,并且因为性能不好。
解析csv数据的正确方法是使用专用的状态机(而不是由正则表达式定义的状态机)。好消息是您不必自己编写该状态机。坏消息是你必须要小心,因为谷歌充斥着坏 javascript csv解析器...例如,我做的快速搜索的当前第一个结果是这里托管的一个坏例子在Stack Overflow本身。该示例过于依赖于正则表达式,后者使用嵌套的引用文本很难。可以构建一个可以正常运行的正则表达式,但它也容易出错,难以维护,表达式的性能通常不会那么好(因为表达式需要进行反向跟踪)。使用正则表达式解析CSV数据几乎与parsing html with regular expressions一样糟糕。
这是我在Google中看到的第一个好的(基于状态机的)示例:
http://yawgb.blogspot.com/2009/03/parsing-comma-separated-values-in.html
这个特殊的解析器假定逗号作为分隔符(与标签,分号或管道相对),假定双重转义引号(引用内引号)文本字段由它们自行转义,如下所示:""
)。如果这与您的数据匹配,那么这个例子可能会很好 - 但同样,这是一个快速搜索;我自己看得太近了。否则,请继续使用谷歌或使用此示例编写自己的。
从那里开始,我很好奇,因为它听起来有点像你可能使用Excel或平面csv文件作为网站的主要数据存储。这也是一个非常糟糕的主意。当您开始让几个人几乎同时使用该页面时,Excel和平面文件都会出现巨大的并发问题。表演也可能是一个问题,尽管我犹豫不决这一点;最好说性能将是你的表现,但平面文件很容易出错。
答案 1 :(得分:1)
这比你想象的要难......
好吧,我的第一篇文章被一个mod方便地删除,因为我发布了一个外部链接到我的OSS CSV解析器项目。
所以...我将发布完整的ND-FSM(非确定性有限状态机)分线器,它是处理包含字符串的值所必需的。
我们走了:
splitLines: function(csv, delimiter) {
var state = 0;
var value = "";
var line = "";
var lines = [];
function endOfRow() {
lines.push(value);
value = "";
state = 0;
};
csv.replace(/(\"|,|\n|\r|[^\",\r\n]+)/gm, function (m0){
switch (state) {
// the start of an entry/value
case 0:
if (m0 === "\"") {
state = 1;
} else if (m0 === "\n") {
endOfRow();
} else if (/^\r$/.test(m0)) {
// carriage returns are ignored
} else {
value += m0;
state = 3;
}
break;
// delimited input
case 1:
if (m0 === "\"") {
state = 2;
} else {
value += m0;
state = 1;
}
break;
// delimiter found in delimited input
case 2:
// is the delimiter escaped?
if (m0 === "\"" && value.substr(value.length - 1) === "\"") {
value += m0;
state = 1;
} else if (m0 === ",") {
value += m0;
state = 0;
} else if (m0 === "\n") {
endOfRow();
} else if (m0 === "\r") {
// Ignore
} else {
throw new Error("Illegal state");
}
break;
// un-delimited input
case 3:
if (m0 === ",") {
value += m0;
state = 0;
} else if (m0 === "\"") {
throw new Error("Unquoted delimiter found");
} else if (m0 === "\n") {
endOfRow();
} else if (m0 === "\r") {
// Ignore
} else {
throw new Error("Illegal data");
}
break;
default:
throw new Error("Unknown state");
}
return "";
});
if (state != 0) {
endOfRow();
}
return lines;
}
如果你理解复杂性理论,这里是映射:
<强>国:强>
注意:这仅处理行分割部分。其余的由一个单独的(并且非常复杂的)正则表达式例程处理。
我不能因为提出使用词法分析器的想法而受到赞扬。这是另一个我未经许可公开命名的开发者。
如果您希望能够处理任何 RFC 4180兼容的CSV数据,而无需亲自实施,请查看我的个人资料中提到的项目。祝你好运......
答案 2 :(得分:0)
我可能会建议在PHP中执行此操作,除非您确实需要在JS中执行此操作;我很确定无论如何都有一个用于处理CSV文件的PHP库。