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

问题描述 投票:0回答:3

我的程序中有一个变量

v
,它可能从一组值中取any

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

我的目标是仅当

v
不是
"x"
"y"
"z"
时才执行一些语句。

我试过了,

  • 对于类 C 语言(其中相等运算符比较 actual 字符串值;例如

    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
条件内的语句总是被执行。我做错了什么吗?

if-statement language-agnostic logical-operators control-flow demorgans-law
3个回答
50
投票

使用

&&
/
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" != "z"
    ,这是 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

如您所见,您的逻辑表达式 always 的计算结果为

true

解决方案

你想要做的是,找到一个计算结果为

true
when

的逻辑表达式

(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-like 语言

      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")

意义

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

这使逻辑更加明显。

特定语言

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


6
投票

我想我会为 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 等现代 shell 也有

[[
,这有点不那么讨厌。

#### 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'
命令和运算符周围没有空格),以及 apparent 引号的可选性.没有引用一个值通常不是 syntax 错误,但是如果你没有引用一个需要引用的值,它会导致严重的不良 semantic 麻烦。 (其他地方有更多关于这个的信息。

这里明显的解决方法是使用

&&
而不是
||
但你还应该注意
[[
通常支持正则表达式,所以你可以说像

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

并且不要忘记可信赖的旧

case
声明这很自然,并且可以追溯到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

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

(对于非 Bourne 系列的 Unix shell 来说,这显然不是一个合适的答案。C 系列的 shell——包括仍然有点流行的

tcsh
——使用的语法据说是“类 C”的,但那是就像无法区分爱丽丝库珀和那个去了仙境的女孩;鱼壳有它自己的特点,我什至没有资格评论。)


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

还有很多方法,就是我懒了

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

© www.soinside.com 2019 - 2024. All rights reserved.