来自 Asad 的 answer 非常出色,因为它允许使用可变长度的正则表达式分隔符(例如 /\s+/g,沿任意长度的空格分割,包括换行符)。但是,它存在一些问题。
- 如果分隔符不使用全局标志,它将中断。
-
exec 可以返回 null 并导致其中断。如果分隔符没有出现在输入字符串中,就会发生这种情况。
- 如果限制大于分隔点,您最终会在字符串上循环,可能会产生意想不到的结果。
- 限制是必需的,因此很难找到最大拆分。
以下解决了这些问题,同时具有同样的性能:
/**
* Split a string with a RegExp separator an optionally limited number of times.
* @param {string} input
* @param {RegExp} separator
* @param {number} [limit] - If not included, splits the maximum times
* @returns {string[]}
*/
function split(input, separator, limit) {
// Ensure the separator is global
separator = new RegExp(separator, 'g');
// Allow the limit argument to be excluded
limit = limit ?? -1;
const output = [];
let finalIndex = 0;
while (limit--) {
const lastIndex = separator.lastIndex;
const search = separator.exec(input);
if (search === null) {
break;
}
finalIndex = separator.lastIndex;
output.push(input.slice(lastIndex, search.index));
}
output.push(input.slice(finalIndex));
return output;
}
split("foo bar baz quux", /\s+/, 3)
// ["foo", "bar", "baz", "quux"]
split("foo bar baz quux", /\s+/, 2)
// ["foo", "bar", "baz quux"]
split("foo bar baz quux", /\s+/, 1)
// ["foo", "bar baz quux"]
split("foo bar baz quux", /\s+/, 0)
// ["foo bar baz quux"]
// A higher limit than possible splits
split("foo bar baz quux", /\s+/, 4)
// ["foo", "bar", "baz", "quux"]
// A split that doesn't exist
split("foo bar baz quux", /p/, 2)
// ["foo bar baz quux"]
// Not providing a limit finds the maximum splits
split("foo bar baz quux", /\s+/)
// ["foo", "bar", "baz", "quux"]
注意事项:
在生产代码中,建议不要改变函数参数。 separator 和 limit 都在发生变异。如果需要,您可以选择在函数顶部创建新变量以避免这种情况。我选择不这样做是为了保持示例代码简短。这不是生产代码。
我没有包含任何防御性代码来检查函数参数类型。这对于生产代码来说是一件好事,或者考虑 TypeScript ;)
如果提供的分隔符没有设置全局标志,我最初会抛出Error。请参阅下面的 cmets,了解可能需要为用户添加全局标志而不是抛出的原因。感谢@Stephen P 的建议。