在 JavaScript 中将大字符串拆分为 n 大小的块

IT技术 javascript regex string split
2021-01-23 20:56:35

我想将一个非常大的字符串(比如 10,000 个字符)拆分为 N 大小的块。

就性能而言,这样做的最佳方法是什么?

例如: "1234567890"被 2 分割将变成["12", "34", "56", "78", "90"]

是否可以使用String.prototype.match这样的东西,如果可以,这是否是性能方面的最佳方法?

6个回答

你可以这样做:

"1234567890".match(/.{1,2}/g);
// Results in:
["12", "34", "56", "78", "90"]

该方法仍然适用于大小不是块大小的精确倍数的字符串:

"123456789".match(/.{1,2}/g);
// Results in:
["12", "34", "56", "78", "9"]

通常,对于您想要从中提取最多n 个大小的子字符串的任何字符串,您可以执行以下操作:

str.match(/.{1,n}/g); // Replace n with the size of the substring

如果您的字符串可以包含换行符或回车符,您可以这样做:

str.match(/(.|[\r\n]){1,n}/g); // Replace n with the size of the substring

至于性能,我尝试了大约 10k 个字符,在 Chrome 上花了一秒钟多一点。天啊。

这也可以用于可重用的函数:

function chunkString(str, length) {
  return str.match(new RegExp('.{1,' + length + '}', 'g'));
}
由于这个答案现在已经快 3 年了,我想再次尝试@Vivin 所做的性能测试。因此,仅供参考,在 Chrome v33 上使用给定的正则表达式将 100k 个字符两两分割是即时的。
2021-03-12 20:56:35
对于任何在 jsperf 上寻找具有性能基准的真正快速字符串分块的人,请参阅我的答案使用正则表达式是最慢的分块方法。
2021-03-20 20:56:35
根据developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...您可以将任何字符(包括换行符)与[^]. 有了这个,你的例子会导致str.match(/[^]{1,n}/g)
2021-03-21 20:56:35
@Fmstrat“如果您的字符串包含空格,则不计入长度”是什么意思?是的,.根本不匹配换行符。我会更新答案,以便它考虑\n\r考虑在内。
2021-03-24 20:56:35
类似的东西var chunks = str.split("").reverse().join().match(/.{1, 4}/).map(function(s) { return s.split("").reverse().join(); });这是以 4 块为单位进行的。我不确定您所说的“更少或更多”是什么意思。请记住,这在一般情况下是行不通的,尤其是对于包含组合字符并且也可能破坏 Unicode 字符串的字符串。
2021-03-27 20:56:35

我创建了几个更快的变体,您可以在 jsPerf 上看到它们我最喜欢的是这个:

function chunkSubstr(str, size) {
  const numChunks = Math.ceil(str.length / size)
  const chunks = new Array(numChunks)

  for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
    chunks[i] = str.substr(o, size)
  }

  return chunks
}
@DavidAnderton 好收获。我修复了它,有趣的是它似乎运行得更快。它在应该Math.ceil()确定正确的块数时进行了四舍五入
2021-03-25 20:56:35
所以这对长字符串(大约 800k - 9m 个字符)非常有效,除非我将大小设置为 20 出于某种原因最后一个块没有返回......非常奇怪的行为。
2021-04-04 20:56:35
谢谢!我把他作为一个 NPM module放在一起,带有可选的 Unicode 支持 - github.com/vladgolubev/fast-chunk-string
2021-04-07 20:56:35

底线:

  • match效率很低,slice更好,在 Firefox 上substr/substring还是更好
  • match 对于短字符串效率更低(即使使用缓存的正则表达式 - 可能是由于正则表达式解析设置时间)
  • match 对于大块大小甚至效率更低(可能是由于无法“跳转”)
  • 对于块大小非常小的较长字符串,在较旧的 IE 上match表现优于slice但在所有其他系统上仍然失败
  • jsperf岩石
jsperf 链接已损坏
2021-04-09 20:56:35

这是一个快速而直接的解决方案 -

function chunkString (str, len) {
  const size = Math.ceil(str.length/len)
  const r = Array(size)
  let offset = 0
  
  for (let i = 0; i < size; i++) {
    r[i] = str.substr(offset, len)
    offset += len
  }
  
  return r
}

console.log(chunkString("helloworld", 3))
// => [ "hel", "low", "orl", "d" ]

// 10,000 char string
const bigString = "helloworld".repeat(1000)
console.time("perf")
const result = chunkString(bigString, 3)
console.timeEnd("perf")
console.log(result)
// => perf: 0.385 ms
// => [ "hel", "low", "orl", "dhe", "llo", "wor", ... ]

@FelipeValdes 我假设不会将它们与全局/参数变量混淆或将它们表示为私有范围。
2021-03-13 20:56:35
你必须使用substr()而不是substring().
2021-03-14 20:56:35
我很好奇,为什么变量名中有下划线?
2021-03-19 20:56:35

惊喜!您可以使用split进行拆分。

var parts = "1234567890 ".split(/(.{2})/).filter(O=>O)

结果是 [ '12', '34', '56', '78', '90', ' ' ]

@BenCarp 这是摩托车操作员。它使它运行得更快。;)
2021-03-17 20:56:35
当前正则表达式在块之间创建空数组元素。filter(x=>x)用于过滤掉那些空元素
2021-03-18 20:56:35
简短而聪明,但多次迭代输入。此答案比此线程中的其他解决方案慢 4 倍以上。
2021-03-30 20:56:35
filter (o=>o)为了什么?
2021-04-06 20:56:35