如何使用JavaScript解析CSV字符串(数据中包含逗号)?
我有以下类型的字符串如何使用JavaScript解析CSV字符串(数据中包含逗号)?,javascript,regex,split,Javascript,Regex,Split,我有以下类型的字符串 var string = "'string, duppi, du', 23, lala" 我想在每个逗号上将字符串分割成一个数组,但仅限于单引号外的逗号 我找不出适合分割的正则表达式 string.split(/,/) 会给我 ["'string", " duppi", " du'", " 23", " lala"] 但结果应该是: ["s
var string = "'string, duppi, du', 23, lala"
我想在每个逗号上将字符串分割成一个数组,但仅限于单引号外的逗号
我找不出适合分割的正则表达式
string.split(/,/)
会给我
["'string", " duppi", " du'", " 23", " lala"]
但结果应该是:
["string, duppi, du", "23", "lala"]
有跨浏览器解决方案吗?如果可以将引号分隔符设置为双引号,则这是的副本 您可以先将所有单引号转换为双引号:
string = string.replace( /'/g, '"' );
…或者您可以编辑该问题中的正则表达式以识别单引号而不是双引号:
// Quoted fields.
"(?:'([^']*(?:''[^']*)*)'|" +
但是,这假设您的问题中不清楚某些标记。根据我对您问题的评论,请澄清标记的各种可能性。根据,此功能应能:
String.prototype.splitCSV = function(sep) {
for (var foo = this.split(sep = sep || ","), x = foo.length - 1, tl; x >= 0; x--) {
if (foo[x].replace(/'\s+$/, "'").charAt(foo[x].length - 1) == "'") {
if ((tl = foo[x].replace(/^\s+'/, "'")).length > 1 && tl.charAt(0) == "'") {
foo[x] = foo[x].replace(/^\s*'|'\s*$/g, '').replace(/''/g, "'");
} else if (x) {
foo.splice(x - 1, 2, [foo[x - 1], foo[x]].join(sep));
} else foo = foo.shift().split(sep).concat(foo);
} else foo[x].replace(/''/g, "'");
} return foo;
};
你可以这样称呼它:
var string = "'string, duppi, du', 23, lala";
var parsed = string.splitCSV();
alert(parsed.join("|"));
这是一种工作方式,但看起来有些元素前面有空格。我的答案假定您的输入是来自web源的代码/内容的反映,其中单引号和双引号字符是完全可互换的,只要它们作为非转义匹配集出现 您不能为此使用正则表达式。实际上,您必须编写一个微型解析器来分析要拆分的字符串。为了回答这个问题,我将把字符串的引用部分称为子字符串。你需要特别地穿过绳子。考虑以下情况:
var a = "some sample string with \"double quotes\" and 'single quotes' and some craziness like this: \\\" or \\'",
b = "sample of code from JavaScript with a regex containing a comma /\,/ that should probably be ignored.";
在这种情况下,通过简单地分析字符模式的输入,您完全不知道子字符串从何处开始或结束。相反,您必须编写逻辑来决定引号字符是否用作引号字符、本身是否未引号以及引号字符是否在转义之后
我不打算为您编写如此复杂的代码,但您可以看看我最近编写的具有您需要的模式的代码。这段代码与逗号无关,但在编写自己的代码时,它是一个足够有效的微解析器。查看以下应用程序的asifix功能:
免责声明
2014-12-01更新:以下答案仅适用于一种非常特定的CSV格式。正如正确指出的,此解决方案不符合RFC 4180对CSV的定义,也不符合Microsoft Excel格式。此解决方案简单地演示了如何解析一行(非标准)CSV输入,其中包含多种字符串类型,其中字符串可能包含转义引号和逗号
非标准CSV解决方案
如前所述,如果希望正确处理可能包含转义字符的带引号的字符串,则确实需要从头到尾解析字符串。此外,OP没有明确定义什么是“CSV字符串”。首先,我们必须定义构成有效CSV字符串的内容及其各个值
给定:“CSV字符串”定义
在本讨论中,“CSV字符串”由零个或多个值组成,其中多个值用逗号分隔。每个值可能包括:
- 引用的值可能包含逗号
- 引用的值可能包含转义的任何内容,例如
“太酷了”
- 包含引号、逗号或反斜杠的值必须加引号
- 必须引用包含前导或尾随空格的值
- 反斜杠将从单引号中的所有:
中删除\'
- 反斜杠将从双引号中的所有:
中删除\“
- 不带引号的字符串将修剪任何前导空格和尾随空格
- 逗号分隔符可能有相邻的空格(忽略)
r'''.'''.''.
raw多行字符串语法表示)
首先,这里是一个正则表达式,用于验证CVS字符串是否满足上述要求:
验证“CSV字符串”的正则表达式:
re_valid=r”“”
#验证具有单引号、双引号或无引号值的CSV字符串。
^#锚定至管柱起点。
\s*#在值之前允许空白。
(?:#为价值选择分组。
“[^'\]*(?:\\[\S\S][^'\]*)*”\35;单引号字符串,
|“[^”\]*(?:\\[\S\S][^”\\]*)*”或双引号字符串,
|[^,“\s\\]*(?:\s+[^,“\s\\]+)*”或非逗号、非引号的内容。
)#价值选择的最终群体。
\s*#允许值后面有空格。
(?:#零个或更多附加值
,#用逗号分隔的值。
\s*#在值之前允许空白。
(?:#为价值选择分组。
“[^'\]*(?:\\[\S\S][^'\]*)*”\35;单引号字符串,
|“[^”\]*(?:\\[\S\S][^”\\]*)*”或双引号字符串,
|[^,“\s\\]*(?:\s+[^,“\s\\]+)*”或非逗号、非引号的内容。
)#价值选择的最终群体。
\*
start
= [\n\r]* first:line rest:([\n\r]+ data:line { return data; })* [\n\r]* { rest.unshift(first); return rest; }
line
= first:field rest:("," text:field { return text; })*
& { return !!first || rest.length; } // ignore blank lines
{ rest.unshift(first); return rest; }
field
= '"' text:char* '"' { return text.join(''); }
/ text:[^\n\r,]* { return text.join(''); }
char
= '"' '"' { return '"'; }
/ [^"]
<?php
session_start(); // Optional
header("content-type: text/xml");
header("charset=UTF-8");
// Set the delimiter and the End of Line character of your CSV content:
echo json_encode(array_map('str_getcsv', str_getcsv($_POST["csv"], "\n")));
?>
function csvToArray(csv) {
var oXhr = new XMLHttpRequest;
oXhr.addEventListener("readystatechange",
function () {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
console.log(JSON.parse(this.responseText));
}
}
);
oXhr.open("POST","path/to/csv.php",true);
oXhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
oXhr.send("csv=" + encodeURIComponent(csv));
}
stringLine = stringLine.replace(/\0/g, "" );
"some ""value"" that is on xlsx file",123
function parse(text) {
const csvExp = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|"([^""]*(?:"[\S\s][^""]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;
const values = [];
text.replace(csvExp, (m0, m1, m2, m3, m4) => {
if (m1 !== undefined) {
values.push(m1.replace(/\\'/g, "'"));
}
else if (m2 !== undefined) {
values.push(m2.replace(/\\"/g, '"'));
}
else if (m3 !== undefined) {
values.push(m3.replace(/""/g, '"'));
}
else if (m4 !== undefined) {
values.push(m4);
}
return '';
});
if (/,\s*$/.test(text)) {
values.push('');
}
return values;
}
String.prototype.splitCSV = function() {
var matches = this.match(/(\s*"[^"]+"\s*|\s*[^,]+|,)(?=,|$)/g);
for (var n = 0; n < matches.length; ++n) {
matches[n] = matches[n].trim();
if (matches[n] == ',') matches[n] = '';
}
if (this[0] == ',') matches.unshift("");
return matches;
}
var string = ',"string, duppi, du" , 23 ,,, "string, duppi, du",dup,"", , lala';
var parsed = string.splitCSV();
alert(parsed.join('|'));
address,pincode
foo,baar , 123456
[{
address: 'foo',
pincode: 'baar',
'field3': '123456'
}]
function csv2arr(str: string) {
let line = ["",];
const ret = [line,];
let quote = false;
for (let i = 0; i < str.length; i++) {
const cur = str[i];
const next = str[i + 1];
if (!quote) {
const cellIsEmpty = line[line.length - 1].length === 0;
if (cur === '"' && cellIsEmpty) quote = true;
else if (cur === ",") line.push("");
else if (cur === "\r" && next === "\n") { line = ["",]; ret.push(line); i++; }
else if (cur === "\n" || cur === "\r") { line = ["",]; ret.push(line); }
else line[line.length - 1] += cur;
} else {
if (cur === '"' && next === '"') { line[line.length - 1] += cur; i++; }
else if (cur === '"') quote = false;
else line[line.length - 1] += cur;
}
}
return ret;
}
function parseCsv(data, fieldSep, newLine) {
fieldSep = fieldSep || ',';
newLine = newLine || '\n';
var nSep = '\x1D';
var qSep = '\x1E';
var cSep = '\x1F';
var nSepRe = new RegExp(nSep, 'g');
var qSepRe = new RegExp(qSep, 'g');
var cSepRe = new RegExp(cSep, 'g');
var fieldRe = new RegExp('(?<=(^|[' + fieldSep + '\\n]))"(|[\\s\\S]+?(?<![^"]"))"(?=($|[' + fieldSep + '\\n]))', 'g');
var grid = [];
data.replace(/\r/g, '').replace(/\n+$/, '').replace(fieldRe, function(match, p1, p2) {
return p2.replace(/\n/g, nSep).replace(/""/g, qSep).replace(/,/g, cSep);
}).split(/\n/).forEach(function(line) {
var row = line.split(fieldSep).map(function(cell) {
return cell.replace(nSepRe, newLine).replace(qSepRe, '"').replace(cSepRe, ',');
});
grid.push(row);
});
return grid;
}
const csv = 'A1,B1,C1\n"A ""2""","B, 2","C\n2"';
const separator = ','; // field separator, default: ','
const newline = ' <br /> '; // newline representation in case a field contains newlines, default: '\n'
var grid = parseCsv(csv, separator, newline);
// expected: [ [ 'A1', 'B1', 'C1' ], [ 'A "2"', 'B, 2', 'C <br /> 2' ] ]
function csvRowToArray(row, delimiter = ',', quoteChar = '"'){
let nStart = 0, nEnd = 0, a=[], nRowLen=row.length, bQuotedValue;
while (nStart <= nRowLen) {
bQuotedValue = (row.charAt(nStart) === quoteChar);
if (bQuotedValue) {
nStart++;
nEnd = row.indexOf(quoteChar + delimiter, nStart)
} else {
nEnd = row.indexOf(delimiter, nStart)
}
if (nEnd < 0) nEnd = nRowLen;
a.push(row.substring(nStart,nEnd));
nStart = nEnd + delimiter.length + (bQuotedValue ? 1 : 0)
}
return a;
}