Предотвратите свойства tainting конструктора RegExp в JavaScript.

Это немного загадка, у меня есть представление о том, как я могу ее исправить, но мне интересно, есть ли (намного) более простой способ.

Короче говоря, всякий раз, когда выполняется регулярное выражение в JavaScript, некоторым свойствам присваиваются значения в конструкторе RegExp. Например:

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

RegExp.input
//-> "football"

RegExp.rightContext
//-> "tball"

Я хотел бы выполнить регулярное выражение, не затрагивая эти свойства. Если это невозможно (и я не думаю, что это так), я бы хотел, по крайней мере, вернуть их к своим предыдущим значениям.

Я знаю, что input/$_ можно записывать, но большинство других - нет. Один из вариантов может состоять в том, чтобы восстановить регулярное выражение, которое будет повторно использовать все эти значения, но я думаю, что это будет довольно сложно.

Причина, по которой я хочу это, заключается в том, что я пишу прокладку собственного API и тестируя ее с помощью набора test262. Сбой теста262 на некоторых тестах, где он проверяет, имеет ли объект RegExp неожиданные значения для этих свойств.

Ответы

Ответ 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 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);

Ответ 2

Вы можете попытаться создать функцию обертки для теста:

var fTest = RegExp.test;
RegExp.test = function() {
    var bReturn = fTest.apply(RegExp, arguments);
    delete RegExp.input;
    delete RegExp.rightContext;
    return bReturn;
}