首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当逗号和引号可能在字段中时,从CSV转换为JSON的最佳方法是什么?

当逗号和引号可能在字段中时,从CSV转换为JSON的最佳方法是什么?
EN

Stack Overflow用户
提问于 2019-12-06 18:33:20
回答 1查看 5.3K关注 0票数 3

我希望能够将CSV转换为JSON。csv以这样的自由文本形式出现(带有换行符):

代码语言:javascript
复制
name,age,booktitle
John,2,Hello World
Mary,3,""Alas, What Can I do?""
Joseph,5,"Waiting, waiting, waiting"

你知道我的问题是文件..。

  • 在某些字段中有一些内部逗号,尽管它们至少包含一个双引号。
  • 文件中可能有双引号。

我希望输出没有任何领先和尾随引号的每个领域..。如何正确地从表示此csv的CSV字符串中解析出JSON对象?(没有引号和尾引号)。

我通常用:

代码语言:javascript
复制
var mycsvstring;
var finalconvertedjson = {};
var headerfields = // get headers here
var lines = mycsvstring.split('\n');


for(var i = 0; i < lines.length; i++) {
// loop through each line and set a key for each header field that corresponds to the appropriate lines[i]    
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-12-06 19:24:09

我的第一个猜测是使用正则表达式。你可以试试我刚刚做过的这个(regex101链路):

代码语言:javascript
复制
/\s*(")?(.*?)\1\s*(?:,|$)/gm

这可以用于提取字段,因此也可以抓取标题。第一个捕获组用作带有反向引用(\1)的可选引号抓取器,因此实际数据位于第二个捕获组中。

这里有一个使用中的例子。在所有情况下,我都必须使用slice来切断最后一次匹配,因为允许使用*通配符(比如f1,,f3)的空白字段将零宽度匹配放在末尾。这比使用正则表达式更容易摆脱代码中的错误。最后,如果标题中没有考虑到一些额外的列,我将'extra_i'作为缺省/占位符值。你应该换掉那部分,以满足你自己的需要。

代码语言:javascript
复制
/**
 * Takes a raw CSV string and converts it to a JavaScript object.
 * @param {string} text The raw CSV string.
 * @param {string[]} headers An optional array of headers to use. If none are
 * given, they are pulled from the first line of `text`.
 * @param {string} quoteChar A character to use as the encapsulating character.
 * @param {string} delimiter A character to use between columns.
 * @returns {object[]} An array of JavaScript objects containing headers as keys
 * and row entries as values.
 */
function csvToJson(text, headers, quoteChar = '"', delimiter = ',') {
  const regex = new RegExp(`\\s*(${quoteChar})?(.*?)\\1\\s*(?:${delimiter}|$)`, 'gs');

  const match = line => [...line.matchAll(regex)]
    .map(m => m[2])  // we only want the second capture group
    .slice(0, -1);   // cut off blank match at the end

  const lines = text.split('\n');
  const heads = headers ?? match(lines.shift());

  return lines.map(line => {
    return match(line).reduce((acc, cur, i) => {
      // Attempt to parse as a number; replace blank matches with `null`
      const val = cur.length <= 0 ? null : Number(cur) || cur;
      const key = heads[i] ?? `extra_${i}`;
      return { ...acc, [key]: val };
    }, {});
  });
}

const testString = `name,age,quote
John,,Hello World
Mary,23,""Alas, What Can I do?""
Joseph,45,"Waiting, waiting, waiting"
"Donaldson Jones"   , sixteen,    ""Hello, "my" friend!""`;

console.log(csvToJson(testString));
console.log(csvToJson(testString, ['foo', 'bar', 'baz']));
console.log(csvToJson(testString, ['col_0']));

作为一项奖励,我编写这篇文章是为了允许传递字符串列表作为标题,因为我第一手地知道并不是所有的CSV文件都有这些字符串。

注意:如果您的值中有新行,则此正则表达式方法不起作用。这是因为它依赖于在换行符处拆分字符串。我确实研究过使用这个正则表达式只在引号之外的新行拆分行,这几乎是有效的,但在超过几行的任何行上都要花费30秒以上的时间。

如果您想获得完整的功能,最好的选择是找到一个现有的解析库,或者编写您自己的解析库:一个计算引号出现的库,以便在您迭代“单元格”时知道您是在“单元格”中还是在“单元格”之外。

票数 16
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59218548

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档