首页 文章

更改RegExp标志

提问于
浏览
14

所以基本上我自己编写了这个函数,以便能够计算String中Substring的出现次数:

String.prototype.numberOf = function(needle) {
  var num = 0,
      lastIndex = 0;
  if(typeof needle === "string" || needle instanceof String) {
    while((lastIndex = this.indexOf(needle, lastIndex) + 1) > 0)
      {num++;} return num;
  } else if(needle instanceof RegExp) {
    // needle.global = true;
    return this.match(needle).length;
  } return 0;
};

该方法本身表现相当不错,基于RegExp和基于字符串的搜索与执行时间相当(在整个庞大的Ray Bradbury的“451 Fahrenheit”上搜索所有“the”的两个~2ms) .

但是,令我感到困扰的是,无法更改提供的RegExp实例的标志 . 在没有提供的正则表达式的全局标志设置为true的情况下调用此函数中的String.prototype.match是没有意义的,因为它只会记录第一次出现 . 你当然可以在传递给函数的每个RegExp上手动设置标志,I 'd however prefer being able to clone and then manipulate the supplied Regular Expression'的标志 .

令人惊讶的是,我不允许这样做,因为RegExp.prototype.global标志(更确切地说是所有标志)似乎是只读的 . 从那里评论出来的第8行 .

所以我的问题是: Is there a nice way of changing the flags of a RegExp object?

我真的不想做这样的事情:

if(!expression.global)
  expression = eval(expression.toString() + "g");

某些实现可能不支持RegExp.prototype.toString事件,只是从Object.prototype继承它,或者它可能完全是不同的格式 . 而这似乎是一个糟糕的编码实践开始 .

4 回答

  • 4

    首先,当 needle 是一个不匹配的正则表达式时,您当前的代码无法正常工作 . 即以下行:

    return this.match(needle).length;
    

    当没有匹配时, match 方法返回 null . 然后,当 nulllength 属性(访问失败)时,会生成JavaScript错误 . 这很容易修复如下:

    var m = this.match(needle);
    return m ? m.length : 0;
    

    现在到手头的问题 . 当你说 globalignoreCasemultiline 是只读属性时,你是对的 . 唯一的选择是创建一个新的RegExp . 这很容易完成,因为正则表达式源字符串存储在 re.source 属性中 . 以下是您的函数的经过测试的修改版本,它修正了上述问题,并在 needle 尚未设置其 global 标志时创建新的RegExp对象:

    String.prototype.numberOf = function(needle) {
        var num = 0,
        lastIndex = 0;
        if (typeof needle === "string" || needle instanceof String) {
            while((lastIndex = this.indexOf(needle, lastIndex) + 1) > 0)
                {num++;} return num;
        } else if(needle instanceof RegExp) {
            if (!needle.global) {
                // If global flag not set, create new one.
                var flags = "g";
                if (needle.ignoreCase) flags += "i";
                if (needle.multiline) flags += "m";
                needle = RegExp(needle.source, flags);
            }
            var m = this.match(needle);
            return m ? m.length : 0;
        }
        return 0;
    };
    
  • 1
    var globalRegex = new RegExp(needle.source, "g");
    

    Live Demo EDIT :m只是为了证明你可以设置多个修饰符

    var regex = /find/;
    var other = new RegExp(regex.source, "gm");
    alert(other.global);
    alert(other.multiline);
    
  • 8

    您可以做的并不多,但强烈建议您避免使用 eval . 您可以扩展RegExp原型来帮助您 .

    RegExp.prototype.flags = function () {
        return (this.ignoreCase ? "i" : "")
            + (this.multiline ? "m" : "")
            + (this.global ? "g" : "");
    };
    
    var reg1 = /AAA/i;
    var reg2 = new RegExp(reg1.source, reg1.flags() + 'g');
    
  • 14
    r = new Regexp(r.source, r.flags + (r.global ? "" : "g"));
    

相关问题