【问题标题】:match regex to array of characters将正则表达式匹配到字符数组
【发布时间】:2015-12-25 00:00:45
【问题描述】:

在我正在制作的页面中,我需要一个具有特定大小的字符串环形缓冲区。我为此目的使用了一个数组,只需推送和取消移动。单个索引是单个字符。从那时起,我不想使用字符串,每次我将一个字符推入缓冲区时都会发生一个副本。现在我需要在这个缓冲区上使用正则表达式。问题在于,现在每次我想匹配我都需要array.join(),这样做的成本相当高......

现在我想知道是否可以直接在字符数组上使用正则表达式,而不是先将其转换为字符串。

我想如果有一个可变字符串类型我永远不会有这个问题......

【问题讨论】:

  • 我猜你可以在 JS 中实现自己的正则表达式引擎,但可能会比加入数组慢。
  • 为什么制作副本很重要?
  • @NiettheDarkAbsol 因为我每秒需要 100000 次操作。每次复制524288个字符是不可行的。
  • 所以你认为 push/unshift 不必复制数组?
  • @melpomene 好吧,我不确定它是否在幕后工作,但不,它似乎没有,因为数组长度被修改并且移位后的元素仍然存在。如果你知道的比我多,请赐教

标签: javascript arrays regex


【解决方案1】:

同意..! JS 字符串是不可变的,但是您对它们的连接会耗费时间的担忧并不是很合理。我可以确认,在 Chrome、Firefox、Opera、IE11 和 Safari 中,对 1,000,000 个随机字符的数组进行 Array.prototype.join() 操作大约需要 10~40 毫秒,具体取决于引擎。是的……就是这样。 (尤其是蜘蛛猴发光)我们来看看

var   arr = [],
    match = [],
  longStr = "",
    count = 1000000,
    start = 0,
      end = 0;

for (var i=0; i<count; i++){
  arr.push((+new Date()*Math.random()).toString(36)[0]);
}
start = performance.now();
longStr = arr.join("");
end = performance.now();
console.log("Concatenation took "+(end-start)+" msecs");
// Concatenation took 10.875 msecs.. Wow Firefox..!
start = performance.now();
match = longStr.match(/7{5,}/g);
!match && (match = [])
end = performance.now();
console.log("Regex match took "+(end-start)+" msecs and found " +match.length+" matches as: ", match);
//Regex match took 6.550000000046566 msecs and found 1 matches as: ["77777"]

所以在进行了这些测试之后,我决定尝试回答您的问题。我们需要发明自己的可变字符串对象。实际上创建它非常简单。具有特殊功能的奇异数组对象,也可以访问Array.prototype 函数。就像一个字符串对象一样,它会有一个名为primitiveValue 的额外属性,每次更新长度属性时,我们将执行this.primitiveValue = this.join(); 操作,以便所有访问length 属性的Array.prototype 函数将自动更新@ 987654329@。如果我们有一个写入繁重的工作流程,这将降低性能。好消息是我们可以完全控制我们如何更新primitiveValue。如果我们愿意,我们可以在每次对长度属性的写访问时跳过更新它,并且可以在将正则表达式应用于字符串内容之前手动进行。或者我们甚至可以将正则表达式函数添加到RingBuffer.prototype 和将primitiveValue 作业连接到它们的猴子补丁。这里有很多可能性。

function RingBuffer(){
    this.primitiveValue = "";
    this.__len;
    Object.defineProperty(this, "length", {
                                             enumerable: true,
                                           configurable: true,
                                                    get: this.getLength,
                                                    set: this.setLength
                                          });
}
RingBuffer.prototype = Array.prototype;
RingBuffer.prototype.constructor = RingBuffer;
RingBuffer.prototype.getLength = function(){
                                   return this.__len;
                                 };
RingBuffer.prototype.setLength = function(val){
                                   this.__len = val;
                                   this.primitiveValue = this.join("");
                                 };
var ringu = new RingBuffer();

所以我用 100,000 个随机字符填充了 ringu。 Chrome 49 上的基准测试是这样的;

var longStr = "",
      count = 100000,
      start = performance.now(),
        end = 0;
for (var i=1; i<=count; i++){
  ringu.push((+new Date()*Math.random()).toString(36)[0]);
  if (!(i % 10000)){
    end = performance.now();
    console.log(i/10000+". 10000 pushes done at :"+(end - start)+" msecs");
    start = end;
  }
}
console.log("ringu is filled with " + count + " random characters");
start = performance.now();
longStr = ringu.join("");
end = performance.now();
console.log("Last concatenation took "+(end-start)+" msecs");

1. 10000 pushes done at :1680.6399999996647 msecs
2. 10000 pushes done at :4873.2599999997765 msecs
3. 10000 pushes done at :8044.155000000261 msecs
4. 10000 pushes done at :11585.525000000373 msecs
5. 10000 pushes done at :14642.490000000224 msecs
6. 10000 pushes done at :17998.389999999665 msecs
7. 10000 pushes done at :20814.979999999516 msecs
8. 10000 pushes done at :24024.445000000298 msecs
9. 10000 pushes done at :27146.375 msecs
10. 10000 pushes done at :30347.794999999925 msecs
ringu is filled with 100000 random characters
Last concatenation took 3.510000000707805 msecs

因此,根据您进行写入的频率或在应用正则表达式之前需要串联primitiveValue 的频率,您可以决定在何处调用this.join(""); 指令。 500K 项 RingBuffer 的平均连接时间将小于 30 毫秒。

嗯...这就是 SpiderMonkey 的结果。因此,如果您要在 Node.Js 上运行类似的代码,最好尝试使用 Spider Monkey 或 ChakraCore 引擎配置的 JXCore,而不是使用 V8 的 Node。

1. 10000 pushes done at :710.310000000005 msecs
2. 10000 pushes done at :1831.4599999999991 msecs
3. 10000 pushes done at :3018.199999999997 msecs
4. 10000 pushes done at :4113.779999999999 msecs
5. 10000 pushes done at :5144.470000000008 msecs
6. 10000 pushes done at :6588.179999999993 msecs
7. 10000 pushes done at :7860.005000000005 msecs
8. 10000 pushes done at :8727.050000000003 msecs
9. 10000 pushes done at :9795.709999999992 msecs
10. 10000 pushes done at :10866.055000000008 msecs
ringu is filled with 100000 random characters
Last concatenation took 1.0999999999912689 msecs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-26
    • 1970-01-01
    • 1970-01-01
    • 2016-06-17
    • 1970-01-01
    • 2014-02-06
    • 1970-01-01
    相关资源
    最近更新 更多