为什么一个变量对多个值的非等式检查总是返回true?

时间:2014-10-13 09:45:14

标签: if-statement language-agnostic control-flow multiple-languages

我的程序中有一个变量v,它可能会从值集中获取任何

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

我的目标是仅在v不是"x""y""z"时才执行某些声明。

我试过了,

  • 用于类C语言(其中相等运算符比较实际字符串值;例如。

    if (v != "x" || v != "y" || v != "z")
    {
        // the statements I want to be executed
        // if v is neither "x", nor "y", nor "z"
    }
    
  • 用于Pascal类语言(例如

    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;
    

if条件中的语句总是被执行。我做错了吗?

3 个答案:

答案 0 :(得分:21)

使用&& / AND / and,而不是|| / OR / or

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

问题

如果始终执行if块,则if块的条件始终计算为true 。逻辑表达式必定是错误的。

让我们为v != "x" || v != "y" || v != "z"的每个值考虑v

  • v = "x"

    v != "x"变为"x" != "x" false
    v != "y"变为"x" != "y" true
    v != "z"变为"x" != "y" true

    表达式的计算结果为false || true || true true

  • v = "y"时,表达式变为

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

    true || false || true true

  • v = "z"时,表达式变为

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

    true || true || false true

  • 对于v的任何其他值,表达式的计算结果为true || true || true true

或者,考虑一下真值表:

       │     A          B          C      │
  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

如您所见,您的逻辑表达式总是评估为true

解决方案

您要做的是,找到一个在

时评估为true的逻辑表达式

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

正确的结构是,

  • 用于类C语言(例如 - (可能需要严格等于运算符!==),

    if (v != "x" && v != "y" && v != "z")
    {
        // the statements I want to be executed
        // if v is neither "x", nor "y", nor "z"
    }
    
  • 用于Pascal类语言

    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;
    

德摩根定律

通过De Morgan's law,表达式也可以重写为(使用C语法)

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

含义

<强> not ((v is "x") or (v is "y") or { {1}}。

这使得逻辑更加明显。

特定语言

某些语言具有用于测试集合中成员资格的特定构造,或者您可以使用数组/列表操作。

答案 1 :(得分:3)

我想我会为Bourne shell脚本提供一个答案,因为语法有点特殊。

在traditional / POSIX sh中,字符串相等性测试是[命令的一个特性(是的,这是一个独特的命令名!),它对引用等有一些讨厌的要求。

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

像Ksh,Bash,Zsh等现代炮弹也有[[,这有点不太讨厌。

#### 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

我们应该强调要求在每个令牌周围留出空格,这是许多初学者忽略的东西(即,在命令和操作符周围没有空格的情况下,你不能说if[[$v$v!='y'),以及明显引用的可选性。未能引用值通常不是语法错误,但如果您未引用需要引用的值,则会导致严重的意外语义问题。 (More on this elsewhere.

这里明显的解决方法是使用&&代替||,但您还应注意[[通常支持正则表达式,因此您可以说

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

并且不要忘记可靠的旧case声明,这对于此非常自然,并且可以移植到20世纪70年代后期:

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

尾随的双分号最初会引起动脉瘤,但你很快就会恢复,并学会欣赏,甚至爱它们。 POSIX允许你在匹配表达式之前放置一个左括号,这样你就没有不成对的右括号,但这种用法并不常见。

(对于不属于Bourne系列的Unix shell来说,这显然不是一个合适的答案.C系列的shell - 包括仍然有点受欢迎的tcsh - 使用的语法应该是“C-就像“但这就像无法将Alice Cooper与去仙境的女孩区分开来;鱼壳有其独特的特点,我甚至无法评论。”

答案 2 :(得分:2)

对于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

对于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

对于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

对于C:

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

还有更多方法,我太懒了。

运用你的想象力,写下你更喜欢的那个!