2013-05-23 10 views
15

To jest trochę problem, mam pomysł, jak mogę to naprawić, ale zastanawiam się, czy istnieje (dużo) łatwiejszy sposób.Zapobieganie właściwościom tępienia konstruktora RegExp w JavaScript

Krótko mówiąc, za każdym razem, gdy w JavaScript jest wykonywane wyrażenie regularne, niektórym właściwościom przypisuje się wartości w konstruktorze RegExp. Na przykład:

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

RegExp.input 
//-> "football" 

RegExp.rightContext 
//-> "tball" 

Chciałbym wykonać wyrażenie regularne bez wpływu na te właściwości. Jeśli to nie jest możliwe (i nie sądzę, że tak jest), chciałbym przynajmniej przywrócić je do ich poprzednich wartości.

Wiem, że input/$_ jest zapisywalny, ale większość innych nie jest, jak się wydaje. Jedną z opcji może być rekonstrukcja wyrażenia regularnego, które będzie ponownie stosować wszystkie te wartości, ale myślę, że byłoby to dość trudne.

Powodem tego chcę, ponieważ piszę shim of a native API i testuję go przy użyciu zestawu test262. Pakiet test262 kończy się niepowodzeniem w przypadku niektórych testów, w których sprawdza, czy obiekt RegExp ma nieoczekiwane wartości dla tych właściwości.

+0

to ma być tymczasowe? –

+4

Podoba mi się zagadka, którą ujawniłeś. Jednak myślę, że zmieniasz część systemu, która nie musi być zmieniana, aby pomieścić zepsutą część: zepsuta część jest twoją ramą testową. Jeśli twój produkt końcowy nie wymaga, aby obiekt RegExp zachował swój pierwotny stan, to nie ma powodu, aby powinieneś pozwolić, aby dowolny test w twojej strukturze zmusił cię do przepisania twojego kodu. Powiedziałbym, że dziełem, które chcesz zmienić, jest framework testowy. Zakładam, że szukałeś opcji konfiguracyjnych i takich, aby zignorować pewien test na obiekcie RegExp? –

+0

@Hurricane: Tak, mógłbym zignorować to i prawie to zrobiłem. Gdyby rozwiązanie nie było tak łatwe, prawdopodobnie bym to zrobił. Ponieważ jednak piszę shim dla natywnego API, chciałem, aby było to jak najbliżej możliwe wdrożenie do pokrycia wszystkich baz. Już kilka razy wygłaszałem przepisy testowe na moją korzyść, jeśli nie jest to możliwe. –

Odpowiedz

1

To jest wynik końcowy. Jest trochę bardziej solidny niż mój pierwszy wysiłek; to właściwie ucieka sub-wyrażeń, pilnuje, pojawiają się one w odpowiedniej kolejności i nie zatrzyma się, gdy stwierdzi pusty jeden:

/** 
* 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; 
} 

Czyni to, co początkowo wydawało się być trudne. To powinno przywrócić wszystkie właściwości do swoich dawnych wartości, jeśli używasz go tak:

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); 
1

Można spróbować utworzyć funkcję otoki do badań:

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

To nie "przywraca" poprzedniego stanu (po prostu usuwa te właściwości z obiektu) i nie działa w Google Chrome, gdzie większość właściwości to gettery. Co więcej, zmienia to zachowanie wbudowanej metody "RegExp.prototype.test", co jest niepożądane. –

Powiązane problemy