为什么对一个变量进行多个值的不相等检查总是返回 true?

Why does non-equality check of one variable against many values always return true?

提问人:sampathsris 提问时间:10/13/2014 最后编辑:Karl Knechtelsampathsris 更新时间:8/30/2023 访问量:3250

问:

我的程序中有一个变量,它可以从值集中获取任何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

C# JavaScript PHP PLSQL IF-语句 与语言无关 逻辑运算符 控制流 demorgans-law sql python java-9

评论

7赞 sampathsris 11/17/2015
这是试图为元帖子 if(var != “x” || var != “y” ...) 的规范、与语言无关的问题所描述的问题类型创建一个规范的问答对。
3赞 Radiodef 9/22/2018
请注意,在 Java 中,与 和 (如 ) 进行比较是不正确的。我们需要改用 .equals 方法,如 (或如果可能是)。有关详细信息,请参阅如何在 Java 中比较字符串?String==!=v != "x"!v.equals("x")!"x".equals(v)vnull
0赞 Karl Knechtel 8/15/2022
Смотритетакже德摩根的规则解释
0赞 MisterMiyagi 12/2/2023
“其中相等运算符比较实际字符串值” 这应该是什么意思?示例中的区别似乎在于布尔运算符的名称/符号,而不是相等运算符的工作方式。知道是否应该查看另一种语言的类 C 语言或类 Pascal 语言类别的决定性因素是什么?

答:

50赞 16 revs, 8 users 39%Veedrac #1

使用 //,而不是 //:&&ANDand||ORor

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

问题

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

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

  • 什么时候v = "x"

    v != "x"成为 ,这是错误的
    成为 ,这是真的
    成为 ,这是真的
    "x" != "x"v != "y""x" != "y"v != "z""x" != "z"

    表达式的计算结果为 ,即为 truefalse || true || true

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

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

    或 ,这是真的true || false || true

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

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

    或 ,这是真的true || true || false

  • 对于 的任何其他值,表达式的计算结果为 ,即 truevtrue || 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

溶液

你要做的是,找到一个计算结果为 when 的逻辑表达式true

(v is not "x")(v is not "y")(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;
    

德摩根定律

根据德摩根定律,表达式也可以改写为(使用类似 C 的语法)

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

意义

不是((v is "x")(v is "y")(v is "z"))

这使得逻辑更加明显。

特定语言

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

2赞 Ismael Miguel 10/14/2014 #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

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

发挥你的想象力,写出你更喜欢的那个!

6赞 tripleee 1/8/2018 #3

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

在传统/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')

这里显而易见的解决方法是 use 而不是 ,但你也应该注意,通常支持正则表达式,所以你可以说这样&&||[[

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

不要忘记这个值得信赖的旧声明,这是很自然的,并且可以移植到 1970 年代后期:case

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--包括仍然有点流行的--使用一种据说是“类似C-like”的语法,但这就像无法区分Alice Cooper和去仙境的女孩一样;鱼壳有它自己的特点,我什至没有资格评论。tcsh