Який синтаксис PowerShell для кількох значень у операторі switch?


80

Я в основному хочу зробити це:

switch($someString.ToLower())
{
    "y", "yes" { "You entered Yes." }
    default { "You entered No." }
}

Відповіді:


91
switch($someString.ToLower()) 
{ 
    {($_ -eq "y") -or ($_ -eq "yes")} { "You entered Yes." } 
    default { "You entered No." } 
}

30
я теж можу це зробити, {$_ -in "y","yes"}але я не впевнений, з якої версії PS.
tkokasih


5
-eq не враховує регістр при виконанні порівняння рядків, тому ToLower не потрібен
Богдан Гаврил MSFT

4
Так само ви можете робити { "y", "yes" -contains $_ } І це також не враховує регістр, тому „ТАК” та „ТАК” тощо, також працюють.
TurtleZero

За switchзамовчуванням також не враховує регістр.
FIL

49

Я виявив, що це працює і здається більш читабельним:

switch($someString)
{
    { @("y", "yes") -contains $_ } { "You entered Yes." }
    default { "You entered No." }
}

Оператор "-contains" виконує пошук, не враховуючи регістр, тому вам не потрібно використовувати "ToLower ()". Якщо ви хочете, щоб він чутливий до регістру, замість цього ви можете використовувати "-ccontains".


45

Ви повинні мати можливість використовувати підстановочний знак для своїх значень:

switch -wildcard ($someString.ToLower())
{
    "y*" { "You entered Yes." }
    default { "You entered No." }
}

Також допускаються регулярні вирази.

switch -regex ($someString.ToLower())
{
    "y(es)?" { "You entered Yes." }
    default { "You entered No." }
}

Документація до комутатора PowerShell: Використання виписки про комутатор


1
Це чудове рішення, хоча "технічно", оскільки я просив використовувати окремі значення, я позначив fletcher як відповідь.
Micah

2
Досить справедливо, хоча інший регулярний вираз, мабуть, міг би зробити те саме.
derekerdmann

2
Підхід до регулярних виразів був би більш стислим.
mseery

3
Вам насправді не потрібно, ToLower()оскільки рівність рядків не враховує регістр за замовчуванням у PowerShell.
dan-gph

7
switch($someString.ToLower())
{
    "yes"   { $_ = "y" }
    "y"     { "You entered Yes." }
    default { "You entered No." }
}

Ви можете довільно розгалужувати, каскадувати та зливати справи таким чином, доки цільовий регістр знаходиться нижче / після справи або випадків, коли змінна $ _ відповідно перепризначена.


nb Настільки ж милою, як така поведінка, здається, виявляється, що інтерпретатор PowerShell не реалізує перемикач / корпус настільки ефективно, як можна було б сподіватися чи припускати. З одного боку, використання налагоджувача ISE передбачає, що замість оптимізованого пошуку, хешування або двійкового розгалуження кожен випадок перевіряється по черзі, як і багато інших операторів if-else. (Якщо це так, спробуйте поставити найпоширеніші випадки на перше місце.) Крім того, як показано у цій відповіді, PowerShell продовжує тестування випадків після того, як їх задовольнив. І досить жорстоко, навіть буває спеціальний оптимізований код перемикання, доступний у .NET CIL, яким через таку поведінку PowerShell не може скористатися.


2
Це не мило - це задокументовано. Додайте оператор break, якщо не хочете, щоб оцінювались наступні гілки.
Френк

2
@Frank Досить справедливо, "милий", можливо, не був найкращим словом для посилання на поведінку ключових слів, яка була змінена або нетипова щодо його історичної семантики у багатьох мовах, починаючи з "C" (1975) або раніше.
Гленн Слейден,

5

Підтримує введення y | ye | yes та не враховує регістр.

switch -regex ($someString.ToLower()) {
        "^y(es?)?$" {
            "You entered Yes." 
        }
        default { "You entered No." }
}

13
Насправді, ваш вираз "[так]" відповідає будь-якому значенню символів "y", "e" або "s" де завгодно в $ someString. Навіть якщо $ someString має значення "ні! Ні! Ні! S", цей блок перемикача поверне "Ви ввели Так". через кінцевий 's'. Для відповідності y | ye | yes вираз повинен бути "^ y (es?)? $".
Lance U. Matthews

5

Невелика модифікація поста derekerdmann для задоволення вихідного запиту за допомогою оператора чергування регулярного виразу "|" (труба).

Також новачкам регулярних статей легше розуміти та читати.

Зауважте, що під час використання регулярного виразу, якщо ви не ставите початок рядкового символу "^" (caret / circumflex) та / або кінець рядкового символу "$" (долар), ви можете отримати несподівану / неінтуїтивну поведінку (наприклад, відповідність " вчора "або" чому ").

Розміщення символів групування "()" (дужки) навколо параметрів зменшує необхідність розміщувати початок і кінець рядкових символів для кожного варіанту. Без них ви отримаєте, можливо, несподівану поведінку, якщо ви не підковані з регулярним виразом. Звичайно, якщо ви не обробляєте введені користувачем дані, а скоріше деякий набір відомих рядків, він буде більш читабельним без групування та початку та кінця символів рядка.

switch -regex ($someString) #many have noted ToLower() here is redundant
{
        #processing user input
    "^(y|yes|indubitably)$" { "You entered Yes." }

        # not processing user input
    "y|yes|indubitably" { "Yes was the selected string" } 
    default { "You entered No." } 
}

-2

Здається, перемикач не чутливий до регістру в PowerShell 5.1. Усі чотири наведені $someStringнижче приклади працюють.

$someString = "YES"
$someString = "yes"
$someString = "yEs"
$someString = "y"

switch ($someString) {
   {"y","yes"} { "You entered Yes." }
   Default { "You didn't enter Yes."}
}

Ось мої $PSVersionTableдані.

Name                           Value
----                           -----
PSVersion                      5.1.17763.771
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.17763.771
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

1
Це неправильна відповідь. Правильним може бути: $ a = 'b'; switch ($ a) {{$ _ -in 'a', 'b'} {'bingo'}; за замовчуванням {'ні!'}}
Мехрдад Мірреза

-4

Після пошуку рішення тієї ж проблеми, що і ви, я знайшов тут цю невеличку тему. Заздалегідь я отримав набагато більш плавне рішення для цього перемикача, виклад справи

switch($someString) #switch is caseINsensitive, so you don't need to lower
{
    { 'y' -or 'yes' } { "You entered Yes." }
    default { "You entered No." }
}

4
{'y' -or 'yes'} завжди вважає істинним, тому гілка за замовчуванням ніколи не потрапляє
Даррен Госбелл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.