2013-05-23 12 views
15

Questo è un po 'un enigma, ho un'idea di come potrei essere in grado di risolverlo ma mi chiedo se c'è un modo (molto) più semplice.Prevenire le proprietà di contaminazione del costruttore RegExp in JavaScript

In breve, ogni volta che un'espressione regolare viene eseguita in JavaScript, a determinate proprietà vengono assegnati valori sul costruttore RegExp. Ad esempio:

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

RegExp.input 
//-> "football" 

RegExp.rightContext 
//-> "tball" 

Mi piacerebbe eseguire un'espressione regolare senza influire su queste proprietà. Se ciò non è possibile (e non penso che lo sia), mi piacerebbe almeno ripristinarli ai valori precedenti in seguito.

Lo so input/$_ è scrivibile, ma la maggior parte degli altri non lo sono, a quanto pare. Un'opzione potrebbe essere quella di ricostruire un'espressione regolare che riapplicherebbe tutti questi valori, ma penso che sarebbe piuttosto difficile.

Il motivo per cui desidero questo è perché sto scrivendo un shim of a native API e lo sto testando utilizzando la suite test262. La suite test262 non riesce su alcuni test in cui viene verificato se l'oggetto RegExp ha valori imprevisti per queste proprietà.

+0

ha a che essere temporaneo? –

+4

Mi piace l'enigma che hai rivelato. Tuttavia, il mio pensiero è che stai cambiando una parte del tuo sistema che non ha bisogno di essere modificato per ospitare una parte rotta: la parte rotta è il tuo framework di test. Se il tuo prodotto finale non richiede che l'oggetto RegExp mantenga il suo stato originale, allora non c'è motivo per cui lasciare che un test arbitrario nel tuo framework ti costringa a riscrivere il tuo codice. Direi che il pezzo che vuoi cambiare è il framework di test. Presumo che hai cercato opzioni di configurazione e tale da ignorare determinati test sull'oggetto RegExp? –

+0

@Hurricane: Sì, potrei scegliere di ignorarlo, e l'ho quasi fatto. Se la soluzione non fosse stata così facile probabilmente lo avrei fatto. Tuttavia, dal momento che sto scrivendo uno shim per un'API nativa, volevo che fosse l'implementazione più vicina possibile a coprire tutte le basi. Ho già piegato le regole del test a mio favore un paio di volte in cui ciò non è possibile, tuttavia. –

risposta

1

Questo è il risultato finale. È un po 'più robusto del mio sforzo iniziale; sfugge correttamente sotto-espressioni, si assicura che appaiono nel giusto ordine e non si ferma quando trova un vuoto uno:

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

Fa quello che ho inizialmente pensato per essere difficile. Questo dovrebbe ripristinare tutte le proprietà ai loro valori precedenti, se lo si utilizza in questo modo:

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

Si può cercare di creare una funzione wrapper per il test:

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

Questo non "ripristina" lo stato precedente (cancella semplicemente quelle proprietà dall'oggetto), e non funziona in Google Chrome dove la maggior parte delle proprietà sono getter. Inoltre, sta cambiando il comportamento del costruito nel 'RegExp.prototype.test' metodo, che è indesiderato. –

Problemi correlati