Почему проверка на неравенство одной переменной по многим значениям всегда возвращает 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"
    }
    
  • для языков, подобных Паскалю (например,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 всегда исполняются. Я делаю что-то не так?

3 ответов


использовать &&/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", который дает ложные.
    v != "y" становится "x" != "y", который дает это правда.
    v != "z" становится "x" != "y", который дает это правда.

    выражение false || true || true, которая составляет правда.


  • , когда v = "y" выражение будет

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

    или true || false || true, который правда.


  • , когда v = "z" выражение будет

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

    или true || true || false, которая составляет правда.


  • для любого другого значения для v, выражение 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-подобных языков (напр. 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"
    }
    
  • на Паскаль-подобных языков 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;
    

By закон де Моргана, выражение также может быть переписано как (с использованием синтаксиса C)

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

смысл

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

это делает логику немного более очевидной.


некоторые языки имеют определенные конструкции для тестирования членства в наборах, или вы можете использовать операции массива / списка.


я решил, что внесу ответ для сценария Bourne shell, так как синтаксис несколько своеобразен.

в традиционном / POSIX sh тест равенства строк является особенностью [ command (да, это отличное имя команды!) который имеет некоторые надоедливые требования по цитированию и т. д.

#### 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-подобный", но это похоже на неспособность отличить Элиса Купера от девушки, которая отправилась в Страну Чудес; и у рыбьей раковины есть свой собственный особенности, которые я даже не компетентен комментировать.)


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

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

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