¿Por qué el control de no igualdad de una variable contra muchos valores siempre devuelve verdadero?

Tengo una variable v en mi progtwig, y ​​puede tomar cualquier valor del conjunto de valores

 "a", "b", "c", ..., "z" 

Y mi objective es ejecutar alguna statement solo cuando v no es "x" , "y" , o "z" .

Yo he tratado,

  • para los lenguajes tipo C (donde los operadores de igualdad comparan los valores reales de las cadenas, por ejemplo, c # , javascript , php )

     if (v != "x" || v != "y" || v != "z") { // the statements I want to be executed // if v is neither "x", nor "y", nor "z" } 
  • para los idiomas similares a Pascal (por ejemplo, plsql )

     IF (v != 'x' OR v != 'y' OR v != 'z') THEN -- the statements I want to be executed -- if v is neither "x", nor "y", nor "z" END IF; 

Las instrucciones dentro de la condición if siempre se ejecutan . ¿Estoy haciendo algo mal?

Usa && / AND / and , no || / OR / or :

 v != "x" && v != "y" && v != "z" 

Si un bloque if se ejecuta siempre, la condición para el bloque if siempre se evalúa como true . La expresión lógica debe estar equivocada.

Consideremos v != "x" || v != "y" || v != "z" v != "x" || v != "y" || v != "z" v != "x" || v != "y" || v != "z" para cada valor de v .

  • Cuando v = "x" ,

    v != "x" convierte en "x" != "x" , lo que da es falso .
    v != "y" convierte en "x" != "y" , que da es verdadero .
    v != "z" convierte en "x" != "y" , lo que da es verdadero .

    La expresión se evalúa como false || true || true false || true || true false || true || true , que es verdad

  • Cuando v = "y" , la expresión se vuelve

     "y" != "x" || "y" != "y" || "y" != "z" 

    o true || false || true true || false || true true || false || true , que es verdad

  • Cuando v = "z" , la expresión se vuelve

     "z" != "x" || "z" != "y" || "z" != "z" 

    o true || true || false true || true || false true || true || false , que es verdad

  • Para cualquier otro valor para v , la expresión se evalúa como true || true || true true || true || true true || true || true , que es verdad

Alternativamente, considere la tabla de verdad:

  │ ABC │ v │ v != "x" v != "y" v != "z" │ A || B || C ───────┼──────────────────────────────────┼────────────── "x" │ false true true │ true "y" │ true false true │ true "z" │ true true false │ true other │ true true true │ true 

Como puede ver, su expresión lógica siempre se evalúa como true .

Lo que quiere hacer es encontrar una expresión lógica que evalúe como true cuando

(v is not "x") and (v is not "y") and (v is not "z") .

La construcción correcta es,

  • para lenguajes tipo C (por ejemplo, c # , javascript – (puede necesitar el operador de igualdad estricta !== ), php )

     if (v != "x" && v != "y" && v != "z") { // the statements I want to be executed // if v is neither "x", nor "y", nor "z" } 
  • para los lenguajes tipo Pascal plsql

     IF (v != 'x' AND v != 'y' AND v != 'z') THEN -- the statements I want to be executed -- if v is neither "x", nor "y", nor "z" END IF; 

Por la Ley de Morgan , la expresión también puede reescribirse como (usando la syntax C)

 !(v == "x" || v == "y" || v == "z") 

sentido

not ((v is "x") or (v is "y") or (v is "z")) .

Esto hace que la lógica sea un poco más obvia.


Algunos idiomas tienen construcciones específicas para probar la pertenencia a conjuntos, o puede usar operaciones de matriz / lista.

  • sql : v NOT IN ('x', 'y', 'z')

  • javascript : ["x", "y", "z"].indexOf(v) == -1

  • python : v not in {"x", "y", "z"}

Pensé que contribuiría una respuesta para el script de shell de Bourne, ya que la syntax es algo peculiar.

En tradicional / POSIX sh la prueba de igualdad de cadenas es una característica del [ comando (sí, ¡ese es un nombre de comando distinto!) Que tiene algunos requisitos molestos para cotizar, etc.

 #### WRONG if [ "$v" != 'x' ] || [ "$v" != 'y'] || [ "$v" != 'z' ]; then : some code which should happen when $v is not 'x' or 'y' or 'z' fi 

Los proyectiles modernos como Ksh, Bash, Zsh, etc. también tienen [[ algo menos molesto.

 #### STILL WRONG if [[ $v != 'x' || $v != 'y' || $v != 'z' ]]; then : some code which should happen when $v is not 'x' or 'y' or 'z' fi 

Debemos destacar el requisito de tener espacios alrededor de cada token, que es algo que muchos principiantes pasan por alto (es decir, no se puede decir if[[$v o $v!='y' sin espacios en blanco alrededor de los comandos y operadores), y la aparente opcionalidad de cotización. Si no se cita un valor, a menudo no se trata de un error de syntax , pero dará lugar a graves problemas semánticos no deseados si no se cita un valor que debe citarse. ( Más sobre esto en otro lugar )

La solución obvia aquí es usar && lugar de || pero también debes tener en cuenta que [[ típicamente es compatible con deportes para expresiones regulares, por lo que puedes decir algo como

 if [[ ! $v =~ ^(x|y|z)$ ]]; then : yeah fi 

y no te olvides de la vieja y confiable statement de case , que es bastante natural para esto, y es portátil hasta fines de la década de 1970:

 case $v in x | y | z) ;; # don't actually do anything in this switch *) # anything else, we fall through to this switch yeah some more yeah in fact, lots of yeah;; esac 

Los puntos y comas dobles finales causan aneurismas al principio, pero te recuperas rápidamente, y aprendes a apreciarlos, incluso a amarlos. POSIX le permite colocar un paréntesis de apertura antes de la expresión de coincidencia para que no tenga pares de paréntesis separados, pero este uso es poco común.

(Obviamente, esta no es una respuesta adecuada para shells Unix que no sean de la familia Bourne. La familia C de shells -incluida la aún bastante popular tcsh usa una syntax que supuestamente es “C-like” pero es como no poder para distinguir a Alice Cooper de la chica que fue al País de las Maravillas, y el caparazón de Pez tiene sus propias peculiaridades que ni siquiera soy competente para comentar).

Podrías usar algo como esto, para PHP:

 if(strpos('xyz',$v[0])===false)//example 1 //strpos returns false when the letter isn't in the string //returns the position (0 based) of the substring //we must use a strict comparison to see if it isn't in the substring if(!in_array($v[0],array('x','y','z')))//example 2 //example 3 $out=array('x'=>1,'y'=>1,'z'=>1); //create an array if(!$out[$v[0]]) //check if it's not 1 if(!preg_match('/^[xyz]$/',$v))//example 4, using regex if(str_replace(array('x','y','z'),'',$v[0]))//example 5 if(trim($v[0],'xyz'))//example 6 

Para Javascript:

 if(~'xyz'.search(v[0]))//example 1(.indexOf() works too) if(!(v[0] in {x:0,y:0,z:0}))//example 2 if(~['x','y','z'].indexOf(v[0]))//example 3, incompatible with older browsers. if(!/^[xyz]$/.match(v))//example 4 if(v.replace(/^[xyz]$/))//example 5 

Para MySQL:

 Select not locate(@v,'xyz'); -- example 1 select @v not in ('x','y','z'); -- example 2 -- repetition of the same pattern for the others 

Para C:

 if(!strstr('xyz',v))//example 1, untested 

Hay más formas, soy demasiado vago.

¡Usa tu imaginación y solo escribe la que más te guste!

    Intereting Posts