2016-05-12 9 views
5

devo un array come questo:Girando una serie di valori e stringhe in un'istruzione if in Javascript

[true, "&&", false]

Il bilancio vero e falso sono generati da condizioni precedenti e spinto su un array (i' Sto cercando di fornire agli utenti un modo per creare autonomamente la logica di base all'interno del mio progetto web).

Quello che non riesco a capire è come trasformare questo array in un vero e proprio if che corre come questo:

if(true && false) { 
// Run Code 
} 

Si noti che a seconda di ciò che l'impostazione utente matrice potrebbe essere la seguente:

[true, "||", false]

if(true || false) { 
    // Run code 
} 

voglio permettere l'array per consentire anche parentesi:

["(", true, "&&", false, ")", "||", true]

dovrebbe diventare:

if((true && false) || true) { 
    // RUN CODE 
} 
+2

domanda importante: possiamo supporre che l'array contiene sempre JS validi, o si potrebbe avere una matrice non valida come '[ '(', ';', vero', ')'] '? –

+1

Salve @Jordash se una qualsiasi risposta ha risolto la tua domanda per favore considera di accettarla cliccando sul segno di spunta. Ciò indica alla comunità più ampia che hai trovato una soluzione e dà una certa reputazione sia al rispondente che a te stesso. Non c'è l'obbligo di farlo. –

+0

@procrastinator Penso che questa domanda provenga da 'Maggio 12', quest'anno non' Maggio '12 ', no? Mi sto perdendo qualcosa? – 1252748

risposta

7

si potrebbe, anche se è il male, utilizzare un eval dopo aver riunito tutti gli elementi dell'array. cioè

var arr = [true, '&&', false]; 
if(eval(arr.join(''))){ 
    // your code 
} 

Aggiornamento:

Sono recentemente pensato a un molto più semplice (non più semplice di eval), ma risposta sicura. Se le uniche operazioni booleane utilizzate sono && e || e le parentesi sono formattate correttamente, è possibile eseguire una serie di regex sostitutive fino a quando non è rimasto un solo valore, "vero" o "falso".

I valori booleani cercare e operazioni possono essere che la seguente e semplificare al vero o falso

true && true == true true && false == false false && true == false false && false == false

lo stesso vale per operazioni OR

true || true == true true || false == true false || true == true false || false == false

Come risultato , possiamo sostituire l'espressione con i loro valori semplificati - vero o falso. Quindi, se ci sono parentesi intorno all'espressione, finirà come '(true)' o '(false)' e possiamo facilmente regex sostituire anche quello.

Possiamo quindi eseguire il ciclo di questa routine finché non viene lasciato un valore, 'true' o 'false'.

, ad es.nel codice

var boolArr = ["(", true, "&&", "(", false, "||", true, ")", ")", "||", true]; 

//Convert the array to a string "(true&&(false||true))||true" 
var boolString = boolArr.join(''); 

//Loop while the boolean string isn't either "true" or "false" 
while(!(boolString == "true" || boolString == "false")){ 

//Replace all AND operations with their simpler versions 
boolString = boolString.replace(/true&&true/g,'true').replace(/true&&false/g,'false'); 
boolString = boolString.replace(/false&&true/g,'false').replace(/false&&false/g,'false'); 

//Replace all OR operations with their simpler versions 
boolString = boolString.replace(/true\|\|true/g,'true').replace(/true\|\|false/g,'true'); 
boolString = boolString.replace(/false\|\|true/g,'true').replace(/false\|\|false/g,'false'); 

//Replace '(true)' and '(false)' with 'true' and 'false' respectively 
boolString = boolString.replace(/\(true\)/g,'true').replace(/\(false\)/g,'false'); 

} 

//Since the final value is a string of "true" or "false", we must convert it to a boolean 
value = (boolString == "true"?true:false); 

annd, se siete veramente pericoloso, è possibile concatenare tutti quei sostituisce insieme

Inoltre, si prega di notare la bella mancanza di ricorsione e l'uso di un solo ciclo

+0

Perché è cattivo? – Jordash

+0

Di solito si chiama male perché le persone potrebbero potenzialmente mettere qualcosa di malizioso nella dichiarazione di valutazione. –

+1

Ho pensato che la tua risposta originale (con il suo avvertimento) fosse soddisfacente, ma la tua risposta regolare è brillante. Ti voterei di nuovo se potessi. –

7

Quello che vuoi è un recursive descent parser.

Il seguente codice gestirà true, false, && e ||, insieme con parentesi (che può essere nidificata).

È possibile aggiungere facilmente altri operatori binari in base alle esigenze.

function process(logic) { 
 
    var result, op, i, par, idx, token; 
 

 
    for(i = 0; i < logic.length; i++) { 
 
    token = logic[i]; 
 
    if(token === '&&' || token === '||') { 
 
     op = token; 
 
    } 
 
    else { 
 
     if(token === '(') { 
 
     for(par = 0, idx = i ; par ; idx++) { //handle nested parentheses 
 
      if  (logic[idx] === '(') par++; 
 
      else if(logic[idx] === ')') par--; 
 
     } 
 
     token = process(logic.slice(i + 1, idx)); 
 
     i = idx + 1; 
 
     } 
 
     
 
     if  (op === '&&') result = result && token; 
 
     else if(op === '||') result = result || token; 
 
     else     result = token; 
 
    } 
 
    }; 
 
    return result; 
 
} //process 
 

 
function print(logic) { 
 
    console.log(logic.join(' ') + ': ' + process(logic)); 
 
} 
 

 
print([true, "&&", false]); //false 
 
print([true, "&&", true]); //true 
 
print([false, "||", true]); //true 
 
print([false, "||", false]); //false 
 
print(["(", true, "&&", false, ")", "||", true]); //true 
 
print(["(", true, "&&", "(", false, "||", true, ")", ")", "||", true]); //true 
 
print([false, "||", "(", "(", true, "&&", "(", false, "||", true, ")", ")", "&&", false, ")"]); //false

+0

Wow, questa è una risposta infernale –

+0

Sì, peccato "eval()" è rischioso, perché semplifica davvero le cose. –

7

Un'altra soluzione con la costruzione di una matrice nidificata se esistono parentesi e con un oggetto per le operazioni, che potrebbe essere facilmente esteso.

Come funziona:

L'array termine viene iterato e un nuovo array è costruire. Per ogni nuova parentesi di apertura, un array vuoto viene assegnato al livello successivo. Tutti i prossimi termini sono ora portati al livello successivo.

Se viene trovata una parentesi di chiusura, il livello effettivo viene riepilogato con calculate e il risultato viene trasferito al livello inferiore successivo.

Al termine, il livello di base viene raggruppato e il risultato restituito.

Per la valutazione viene utilizzato un oggetto con funzioni per i simboli di funzione binaria.

function process(logic) { 
 

 
    function calculate(a) { 
 
     while (a.length > 2) { 
 
      a.splice(0, 3, op[a[1]](a[0], a[2])); 
 
     } 
 
     return a[0]; 
 
    } 
 

 
    var op = { 
 
      '&&': function (a, b) { return a && b; }, 
 
      '||': function (a, b) { return a || b; } 
 
     }, 
 
     array = [[]], 
 
     level = 0; 
 

 
    logic.forEach(function (a) { 
 
     if (a === '(') { 
 
      ++level; 
 
      array[level] = []; 
 
      return; 
 
     } 
 
     if (a === ')') { 
 
      --level; 
 
      array[level].push(calculate(array[level + 1])); 
 
      return; 
 
     } 
 
     array[level].push(a); 
 
    }); 
 
    return calculate(array[0]); 
 
} 
 

 
function print(logic) { 
 
    document.write(logic.join(' ') + ': <strong>' + process(logic) + '</strong><br>'); 
 
} 
 

 
print([true, "&&", false]); //false 
 
print([true, "&&", true]); //true 
 
print([false, "||", true]); //true 
 
print([false, "||", false]); //false 
 
print(["(", true, "&&", false, ")", "||", true]); //true 
 
print(["(", true, "&&", "(", false, "||", true, ")", ")", "||", true]); //true 
 
print([false, "||", "(", "(", true, "&&", "(", false, "||", true, ")", ")", "&&", false, ")"]); //false

+1

Ben giocato, e tu mi hai ispirato a semplificare la mia risposta. –

+0

@RickHitchcock e Nina Schloz, mi sono appena reso conto che tutto ciò può essere fatto facilmente sostituendo un gruppo di Regex. Idk, perché non ci avevo pensato prima. L'ho aggiunto alla mia risposta se uno di voi è curioso. –

Problemi correlati