15

这有点难题,我知道如何解决它,但我想知道是否有(更)更简单的方法。

简而言之,每当在 JavaScript 中执行正则表达式时,都会在构造函数中为某些属性赋值RegExp。例如:

/foo/.test('football')
//-> true

RegExp.input
//-> "football"

RegExp.rightContext
//-> "tball"

我想在不影响这些属性的情况下执行正则表达式。如果那不可能(而且我认为不可能),我想至少在之后将它们恢复到以前的值。

我知道input/$_是可写的,但似乎其他大多数都不是。一种选择可能是重建一个将重新应用所有这些值的正则表达式,但我认为这将非常困难。

我想要这个的原因是因为我正在编写一个原生 API 的垫片,并使用 test262 套件对其进行测试。test262 套件在某些测试中失败,它会检查 RegExp 对象是否具有这些属性的意外值。

4

2 回答 2

1

这是最终的结果。它比我最初的努力要强大一点;它正确地转义子表达式,确保它们以正确的顺序出现,并且在找到空表达式时不会停止:

/**
 * Constructs a regular expression to restore tainted RegExp properties
 */
function createRegExpRestore () {
    var lm  = RegExp.lastMatch,
        ret = {
           input: RegExp.input
        },
        esc = /[.?*+^$[\]\\(){}|-]/g,
        reg = [],
        cap = {};

    // Create a snapshot of all the 'captured' properties
    for (var i = 1; i <= 9; i++)
        cap['$'+i] = RegExp['$'+i];

    // Escape any special characters in the lastMatch string
    lm = lm.replace(esc, '\\$0');

    // Now, iterate over the captured snapshot
    for (var i = 1; i <= 9; i++) {
        var m = cap['$'+i];

        // If it's empty, add an empty capturing group
        if (!m)
            lm = '()' + lm;

        // Else find the escaped string in lm wrap it to capture it
        else
            lm = lm.replace(m.replace(esc, '\\$0'), '($0)');

        // Push to `reg` and chop `lm`
        reg.push(lm.slice(0, lm.indexOf('(') + 1));
        lm = lm.slice(lm.indexOf('(') + 1);
    }

    // Create the property-reconstructing regular expression
    ret.exp = RegExp(reg.join('') + lm, RegExp.multiline ? 'm' : '');

    return ret;
}

它完成了我最初认为困难的事情。如果您像这样使用它,这应该将所有属性恢复为其以前的值:

var 
    // Create a 'restore point' for RegExp
    old  = createRegExpRestore(),

    // Run your own regular expression
    test = someOtherRegEx.test(someValue);

// Restore the previous values by running the RegExp
old.exp.test(old.input);
于 2013-05-23T12:19:32.367 回答
1

您可以尝试为测试创建一个包装函数:

var fTest = RegExp.test;
RegExp.test = function() {
    var bReturn = fTest.apply(RegExp, arguments);
    delete RegExp.input;
    delete RegExp.rightContext;
    return bReturn;
}
于 2013-07-10T05:24:54.327 回答