【问题标题】:Testing for equality of regular expressions测试正则表达式的相等性
【发布时间】:2012-06-02 08:17:48
【问题描述】:

我很惊讶

/a/ === /a/

在 JavaScript 中计算为 false。通读the specs

程序中的两个正则表达式文字计算为正则 永远不会作为 === 相互比较的表达式对象,即使 两个字面量的内容是相同的。

既然===不能用于测试相等性,那么在JavaScript中如何测试正则表达式的相等性呢?

【问题讨论】:

  • 您说的是 JavaScript,[] == [] 计算结果为 False 的语言。
  • @SivaCharan 这有什么用?
  • @TylerCrompton:别忘了[] == [].lengthThis question 可能会回答最初的问题,或者至少将 OP 推向正确的方向。
  • 这里没有什么特别的 - 这是预期的和合乎逻辑的行为。 RegExp 不是一个特殊的对象,如字符串、对象和数组 - 你也不会期望 new MyClass(x) === new MyClass(x) 是真的。

标签: javascript


【解决方案1】:

这是一个甚至涵盖标志排序的案例。

function regexEqual(x, y) {
    return (x instanceof RegExp) && (y instanceof RegExp) && 
           (x.source === y.source) && (x.global === y.global) && 
           (x.ignoreCase === y.ignoreCase) && (x.multiline === y.multiline);
}

测试:

regexEqual(/a/, /a/) // true
regexEqual(/a/gi, /a/ig) // also true.
regeXEqual(/a/, /b/) // false

【讨论】:

  • 不是和打电话.toString()一样吗?
  • @Eric:不。.toString() 返回您输入的确切内容。这使用预定义的标志顺序来确保 /a/gi === /a/ig。跨度>
  • 非常好。我不知道.source & co。 +1
  • @JohnathonArka:啊,没想到标志的顺序。
  • 您没有检查所有标志,只有gim。例如,对于您的函数,regexEqual(/a/s, /a/) 将返回 true。您还需要检查dotAll (s)、unicode (u) 和sticky (y) 属性。您可以找到完整的标志列表here
【解决方案2】:

这是一个完全测试所有相关正则表达式属性并确保它是正确类型的对象的函数:

function regexSame(r1, r2) {
    if (r1 instanceof RegExp && r2 instanceof RegExp) {
        var props = ["global", "multiline", "ignoreCase", "source", "dotAll", "sticky", "unicode"];
        for (var i = 0; i < props.length; i++) {
            var prop = props[i];
            if (r1[prop] !== r2[prop]) {
                return false;
            }
        }
        return true;
    }
    return false;
}

而且,由于标志有时会被添加到具有新功能的正则表达式对象中(自 2012 年的原始答案以来发生的情况 - 尽管上述代码已于 2019 年更新),所以这里有一个更适合未来证明的版本在添加未来的标志时,因为它比较那里的任何标志,而不是寻找一组特定的标志。它在比较之前对标志进行排序,以允许在指定正则表达式的方式上存在细微差异,而这些差异实际上不会改变功能。

function regexSame(r1, r2) {
    return r1 instanceof RegExp && 
           r2 instanceof RegExp &&
           r1.source === r2.source &&
           r1.flags.split("").sort().join("") === r2.flags.split("").sort().join("");
}

【讨论】:

  • 您没有检查所有标志,只有gim。例如,对于您的函数,regexSame(/a/s, /a/) 将返回 true。您还需要检查dotAll (s)、unicode (u) 和sticky (y) 属性。您可以找到完整的标志列表here
  • @DonaldDuck - 好的,我添加了这些属性。我不确定这些属性在 2012 年编写此答案时是否已记录(甚至可能支持)。无论如何,它现在已经更新了。
  • @DonaldDuck - 我添加了更多面向未来的版本,将来添加新标志时将继续工作。
  • 从 2019-12-06 开始,Edge 不支持正则表达式中的 flags 属性。 Can I use RegExp Flags 在 Edge 支持之前,第一个答案可能是一个更好的主意。
  • @DanHooper - 希望很快,因为 Edge 正在切换到 Chromium 引擎。我想这也意味着 Chrome JS 引擎。
【解决方案3】:

使用toString() 比较它们,并检查它们的type

var a = /a/,
    b = /a/;

a.toString() === b.toString() && typeof(a) === typeof(b)  //true

var c = /a/,
    d = /b/;

c.toString() === d.toString() && typeof(c) === typeof(d)  //false

【讨论】:

    【解决方案4】:

    您可以使用typeof 检查类型,然后使用toString() 两个正则表达式并进行比较。不过,它不会涵盖具有等效标志的情况,例如 /a/gi/a/ig

    function regexEquals(a, b)
    {
        if (typeof a !== 'object' || typeof b !== 'object') return false;
    
        return a.toString() === b.toString();
    }
    

    不幸的是,typeof 没有更具体的类型,所以如果你真的想确保它们是正则表达式(或类似正则表达式),你可以按照以下方式做一些事情:

    RegExp.prototype.regexEquals = function (other)
    {
        return (typeof other.regexEquals === 'function')
            && (this.toString() === other.toString());
    }
    

    然后:

    /a/.regexEquals(/a/); // true
    /a/.regexEquals(/b/); // false
    

    【讨论】:

    • 您也可以使用x instanceof RegExp 来检查x 是否为正则表达式。
    【解决方案5】:

    上述答案未考虑区分大小写。所以基于jfriend00's answer,函数应该是

    function regexEqual(a, b) {
        if (!(a instanceof RegExp) || !(b instanceof RegExp)) {
            return false;
        }
        let sourceA = a.source;
        let sourceB = b.source;
        const flagsA = a.flags.split('').sort().join(',');
        const flagsB = b.flags.split('').sort().join(',');
        if (flagsA.includes('i') && flagsB.includes('i')) {
            sourceA = sourceA.toLowerCase();
            sourceB = sourceB.toLowerCase();
        }
        return sourceA === sourceB && flagsA === flagsB;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-12
      • 2016-06-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多