更新:
我认为一行中的最终版本应该是:
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 种可能性:
-
*?([^",]+?) *?,,这是一个没有" 或, 的字符串,用空格包围,后跟,。
-
" *?(.+?)" *?,,它是一个字符串,由一对引号和引号外不定数量的空格包围,后跟一个,。
-
( *?),,是不定数量的空格,后跟一个','。
因此,由这三个联合的非捕获组拆分基本上可以让我们找到答案。
回想一下,当使用正则表达式拆分时,结果数组包括:
- 用分隔符分隔的字符串(正则表达式)
- 分隔符中的所有捕获组
在我们的例子中,分隔符填充了整个字符串,所以被分隔的字符串都是空字符串,除了最后一个想要的部分,因为没有,在它后面。因此结果数组应该是这样的:
- 一个空字符串
- 三个字符串,代表匹配的第一个分隔符的三个捕获组
- 一个空字符串
- 三个字符串,表示匹配的第二个分隔符的三个捕获组
- ...
- 一个空字符串
- 最后一个想要的部分,别管了
那么为什么要简单地在末尾添加一个, 以便我们可以得到一个完美的模式呢?这就是(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)