如何在忽略引号内的逗号的情况下按逗号分开?

时间:2019-08-20 15:12:09

标签: regex typescript csv

我有一个Typescript文件,该文件需要一个csv文件,并使用以下代码对其进行拆分:

var cells = rows[i].split(",");

我现在需要解决此问题,以使引号内的任何逗号都不会引起拆分。例如,The,"quick, brown fox", jumped应该拆分为Thequick, brown foxjumped,而不是也拆分quickbrown fox。正确的方法是什么?

1 个答案:

答案 0 :(得分:1)

更新:

我认为一行的最终版本应该是:

var cells = (rows[i] + ',').split(/(?: *?([^",]+?) *?,|" *?(.+?)" *?,|( *?),)/).slice(1).reduce((a, b) => (a.length > 0 && a[a.length - 1].length < 4) ? [...a.slice(0, a.length - 1), [...a[a.length - 1], b]] : [...a, [b]], []).map(e => e.reduce((a, b) => a !== undefined ? a : b, undefined))

或者说得更漂亮:

var cells = (rows[i] + ',')
  .split(/(?: *?([^",]+?) *?,|" *?(.+?)" *?,|( *?),)/)
  .slice(1)
  .reduce(
    (a, b) => (a.length > 0 && a[a.length - 1].length < 4)
      ? [...a.slice(0, a.length - 1), [...a[a.length - 1], b]]
      : [...a, [b]],
    [],
  )
  .map(
    e => e.reduce(
      (a, b) => a !== undefined ? a : b, undefined,
    ),
  )
;

这很长,但看起来仍然完全是功能。让我解释一下:

首先,正则表达式部分。基本上,您想要的细分可能会分为3种可能性:

  1. *?([^",]+?) *?,,这是一个字符串,其中没有",并用空格包围,后面跟着,
  2. " *?(.+?)" *?,,它是一个字符串,由一对引号和引号后的不确定数量的空格包围,后跟,
  3. ( *?),,它是一个不确定的空格,后跟一个','。

因此,将这三个部分的一个非捕获组分割成一个联合基本上可以使我们得到答案。

回想一下,使用正则表达式拆分时,结果数组由以下组成:

  1. 用分隔符(正则表达式)分隔的字符串
  2. 分隔符中的所有捕获组

在我们的例子中,分隔符填充了整个字符串,因此,被分隔的字符串都是空字符串,但最后一个所需部分除外,该部分被省略了,因为后面没有,。因此,结果数组应类似于:

  1. 一个空字符串
  2. 三个字符串,代表匹配的第一个分隔符的三个捕获组
  3. 一个空字符串
  4. 三个字符串,代表匹配的第二个分隔符的三个捕获组
  5. ...
  6. 一个空字符串
  7. 最后一个想要的部分,一个人呆着

那为什么只在末尾添加一个,以便我们得到一个完美的模式呢? (rows[i] + ',')就是这样产生的。

在这种情况下,结果数组将变为捕获组,这些组由空字符串分隔。删除第一个空字符串,它们将以4个一组的形式显示为[第一捕获组,第二捕获组,第三捕获组,空字符串]。

reduce块所做的就是将它们精确地分为4组:

  .reduce(
    (a, b) => (a.length > 0 && a[a.length - 1].length < 4)
      ? [...a.slice(0, a.length - 1), [...a[a.length - 1], b]]
      : [...a, [b]],
    [],
  )

最后,找到第一个非undefined元素(一个不匹配的捕获组将显示为undefined。我们的三个模式是互斥的,因为它们中的任意两个不能同时匹配。每一组中恰好有1个这样的元素),它们正是所需的部分:

  .map(
    e => e.reduce(
      (a, b) => a !== undefined ? a : b, undefined,
    ),
  )

这完成了解决方案。


我认为以下内容就足够了:

var cells = rows[i].split(/([^",]+?|".+?") *, */).filter(e => e)

或者如果您不想引号:

var cells = rows[i].split(/(?:([^",]+?)|"(.+?)") *, */).filter(e => e)