Почему проверка равноценности одной переменной по многим значениям всегда возвращает true?

У меня есть переменная 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 != "x" || v != "y" || v != "z" 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 false || true || true false || true || true , что верно .

  • Когда v = "y" , выражение становится

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

    или true || false || true true || false || true true || false || true , что верно .

  • Когда v = "z" , выражение становится

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

    или true || true || false true || true || false true || true || false , что верно .

  • Для любого другого значения для v выражение вычисляется как true || true || true true || true || true true || true || true , что верно .

В качестве альтернативы рассмотрим таблицу истинности:

  │ 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 

Как вы можете видеть, ваше логическое выражение всегда имеет значение 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; 

По закону Моргана выражение также можно переписать как (используя синтаксис Си)

 !(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')

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

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

Я полагал, что внес бы ответ на сценарий оболочки Bourne, поскольку синтаксис несколько свойственен.

В традиционном / 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' без пробелов вокруг команд и операторов), и кажущееся опциональность цитирования. Неспособность указать значение часто не является синтаксической ошибкой, но это приведет к серьезным нежелательным семантическим проблемам, если вы не укажете значение, которое должно быть указано. ( Больше об этом в другом месте. )

Очевидное решение здесь – использовать && вместо || но вы также должны заметить, что [[ обычно спортивная поддержка регулярных выражений, поэтому вы можете сказать что-то вроде

 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 позволяет помещать открывающую скобку перед выражением соответствия, поэтому у вас нет непарных правых круглых скобок, но это использование довольно необычно.

(Это, очевидно, не подходит для оболочек Unix, которые не относятся к семейству Bourne. Семейство C-оболочек, включая еще несколько популярный tcsh использует синтаксис, предположительно «C-like», но это похоже на невозможность рассказать обо всем Элис Купер от девушки, которая отправилась в Страну Чудес, а у рыбской раковины есть свои особенности, о которых я даже не могу комментировать.)

Вы можете использовать что-то вроде этого, для 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 

Есть больше способов, я просто слишком ленив.

Используйте свое воображение и просто напишите то, что вам нравится больше!

  • Выбор случайного элемента из набора
  • «Escape-space» escape-символ «\ b»: неожиданное поведение?
  • Какое распределение вы получаете от этой случайной случайной перетасовки?
  • Что такое «Execute Around» идиома?
  • Можете ли вы объяснить концепцию streamов?
  • Какое лучшее имя для не-мутирующего метода «добавить» в неизменяемой коллекции?
  • В чем разница между IF-ELSE и SWITCH?
  • Когда я должен высмеивать?
  • Определение и реализация статического polymorphismа
  • Как выполняется дифференциальное выполнение?
  • Рассчитайте, когда будет выполняться задание cron, а затем в следующий раз
  • Давайте будем гением компьютера.