我的程序中有一个变量
v
,它可能会从值集中获取任何值
"a", "b", "c", ..., "z"
我的目标是仅当
v
不是 "x"
、"y"
或 "z"
时才执行某些语句。
我已经尝试过了,
对于类 C 语言(其中相等运算符比较 实际字符串值;例如 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"
}
适用于类似 Pascal 的语言(例如 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;
if
条件内的语句总是被执行。我是不是做错了什么?
使用
&&
/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
(v is not "x")
and
(v is not "y")
and
(v is not "z")
.
正确的结构是,
对于类 C 语言(例如 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"
}
用于类似 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;
根据德摩根定律,表达式也可以重写为(使用类C语法)
!(v == "x" || v == "y" || v == "z")
意义
not
((v is "x")
or
(v is "y")
or
(v is "z"))
.
这使得逻辑更加明显。
某些语言具有用于测试集合中的成员资格的特定构造,或者您可以使用数组/列表操作。
sql:
v NOT IN ('x', 'y', 'z')
!["x", "y", "z"].includes(v)
v not in {"x", "y", "z"}
java:
!Arrays.asList("x", "y", "z").contains(v)
java-9(及以上):
!Set.of("x", "y", "z").contains(v)
我想我应该为 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'
),以及 明显 引用的可选性。未能引用某个值通常不是“语法”错误,但如果未能引用需要引用的值,则会导致严重的、不受欢迎的“语义”问题。 (其他地方有更多相关内容。)
这里明显的解决方法是使用 &&
而不是 ||
但您还应该注意
[[
通常支持正则表达式,因此您可以说类似 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”的语法,但这就是就像无法区分爱丽丝·库珀和去了仙境的女孩;鱼壳有它自己的特点,我什至没有能力评论。)
对于 PHP,您可以使用类似的东西:
对于 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
方法还有很多,只是我太懒了
发挥你的想象力,写出你更喜欢的一篇!