A SWITCH kulcsszóval nagyon bonyolult IF/ELSEIF/ELSE feltételrendszerek tudunk nagyon átláthatóan, egyszerűen megvalósítani. Sőt! Még akár bonyolultabb ForEach-Object vagy Where-Object cmdleteket is tudunk helyettesíteni ezzel úgy, hogy a szkriptünk sokkal átláthatóbb és egyszerűbb lesz. Nézzünk erre egy példát, először egy IF szerkezet kiváltására:
[46] PS C:\> $a = 1
[47] PS C:\> if($a -gt 10){"nagyobb mint 10"}elseif($a -gt 5) {"kisebbegyenl
ő 10, nagyobb 5"} else{"kisebbegyenlő 5"}
kisebbegyenlő 5
Ennek switch-et alkalmazó megfelelője:
[48] PS C:\> switch($a)
>> { {$a -gt 10} {"nagyobb mint 10"}
>> {$a -gt 5} {"kisebbegyenlő 10, nagyobb 5"}
>> default {"kisebbegyenlő 5"}
>> }
>>
kisebbegyenlő 5
Vajon tényleg ekvivalens egymással? Nézzük meg, hogy mi van akkor, ha $a=15:
[49] PS C:\> $a = 15
[50] PS C:\> if($a -gt 10){"nagyobb mint 10"}elseif($a -gt 5){"kisebbegyenlő 10, nagyobb 5"}else{"kisebbegyenlő 5"}
nagyobb mint 10
Switch-csel:
[52] PS C:\> switch($a)
>> { {$a -gt 10} {"nagyobb mint 10"}
>> {$a -gt 5} {"kisebbegyenlő 10, nagyobb 5"}
>> default {"kisebbegyenlő 5"}
>> }
>>
nagyobb mint 10
kisebbegyenlő 10, nagyobb 5
Azt láthatjuk itt, hogy a switch különböző sorai nem igazi ELSEIF módon működnek, azaz nem csak akkor adódik rájuk a vezérlés, ha a megelőző sorok nem adtak eredményt, hanem minden esetben. Ha ezt nem szeretnénk, akkor használjuk a BREAK kulcsszót:
[53] PS C:\> switch($a)
>> { {$a -gt 10} {"nagyobb mint 10"; break}
>> {$a -gt 5} {"kisebbegyenlő 10, nagyobb 5"; break}
>> default {"kisebbegyenlő 5"}
>> }
>>
nagyobb mint 10
Ez már ugyanazt a kimenetet adta, mint az IF-es megoldás. Tulajdonképpen a default ág előtti break felesleges, mert oda a vezérlés csak akkor kerül, ha egyik megelőző feltétel sem teljesül, de ha kiírjuk, akkor sem okoz ez semmilyen problémát.
A fenti példák talán még nem érzékeltetik eléggé a switch előnyét, hiszen itt csak egy háromtagú IF láncolatot helyettesítettem. Többtagú kifejezés esetén jobban látszódna a switch átláthatósága, bár így is, a legbeágyazottabb ELSE ág helyett sokkal szebben néz ki egy default címke.
Még jobban kiviláglik a switch egyszerűsége, ha egyenlőségre vizsgálunk, hiszen ekkor nem kell külön az egyenlőség operátort sem használni:
[1] PS C:\> $a = 10
[2] PS C:\> switch($a){ 1 {"egy"} 2 {"kettő"} 3 {"három"} 10 {"tíz"} default {"egyéb"}}
tíz
De itt nem is ér véget a switch előnye, mert – ellentétben az IF-fel – a switch még gyűjteményeket is képes kezelni, így nagyon jó alternatívája lehet a ForEach-Object és a Where-Object cmdleteknek is. Például egy „ékezetlenítő” szkript csak ennyiből áll:
[42] PS C:\> $a = "öt új űrírás az ütvefúrógépen"
[43] PS C:\> $ofs="";"$(switch([char[]] $a){'á' {'a'} 'é' {'e'} 'í' {'i'} 'ó' {'o'} 'ö' {'o'} 'ő' {'o'} 'ú' {'u'} 'ü' {'u'} 'ű' {'u'} default {$_}})"
ot uj uriras az utvefurogepen
Itt a switch megkapja az $a sztringből képzett karaktertömböt ([char[]]), majd a sok karaktercserét megvalósító switch tag után visszakonvertálom a karaktersorozatot adó kimenetet (az egész kifejezés $()-ben) sztringgé (””), de úgy, hogy ne legyen elválasztó szóköz karakter a betűk között ($ofs=””).
Megjegyzés
Bár nem használtam a fenti példában explicit csövet, azaz a „|” csőjelet, de mégis hivatkozható a switch-ben a $_ változó.
És még itt sem ér véget a switch lehetőség-tára. Gyakran foglalkozunk szövegek vizsgálatával, így például ilyen jellegű kifejezések is gyakran szükségessé válnak:
[44] PS C:\> $a = "szöveg"
[45] PS C:\> switch ($a) {{$a -like "s*"} {"s-sel kezdődik"} {$a -like "z*"} {"z-vel kezdődik"}}
s-sel kezdődik
Ha ezt próbálnánk egyszerűbben írni, és kihagyjuk a „-like” operátort, akkor nem kapunk jó eredményt:
[46] PS C:\> switch($a){s* {"s-sel kezdődik"} z* {"z-vel kezdődik"}}
[47] PS C:\>
Hiszen ekkor a switch egyenlőséget vizsgált. Ha –like feltétel van mindenütt, akkor a switch –wildcard kapcsolójával tudjuk az alaphelyzet szerinti egyenlőségvizsgálatot ‑like vizsgálattá alakítani:
[48] PS C:\> switch -wildcard ($a) {s* {"s-sel kezdődik"} z* {"z-vel kezdődik"}}
s-sel kezdődik
Szintén gyakori eset a szövegminták vizsgálata, mint ahogy erre már láttunk példát a 1.4.7 Regex (-match, -replace, -cmatch, -creplace) fejezetben. A switch erre is fel van készítve:
[3] PS C:\> $vizsgálandó="telefon: (30) 311-6867"
[4] PS C:\> switch -regex ($vizsgálandó)
>> {'\((\d{1,2})\)(-|\s)' {"Körzetszám: $($matches[1])"; break}
>> default {"Nincs körzetszám"}}
>>
Körzetszám: 30
[5] PS C:\> $vizsgálandó = "Telefon: 123-4567"
[6] PS C:\> switch -regex ($vizsgálandó)
>> {'\((\d{1,2})\)(-|\s)' {"Körzetszám: $($matches[1])"; break}
>> default {"Nincs körzetszám"}}
>>
Nincs körzetszám
A fenti példában zárójelek közti 1 vagy 2 számjegyből álló mintát keresek a vizsgálandó szövegben, amely mintát vagy szóköz, vagy kötőjel követ. Ha van ilyen, akkor a regex belső csoportképzésével kiadódó zárójelek közti számot adom vissza körzetszám gyanánt, egyébként kiíratom, hogy nincs körzetszám.
Sőt! Még a -casesensitive kapcsolóval kis-nagybetű érzékennyé is tehetjük:
PS C:\> switch -regex -casesensitive ("BC"){"C"{"kis c"}default{"nincs kis c"}}
kis c
PS C:\> switch -regex -casesensitive ("BC"){"c"{"kis c"}default{"nincs kis c"}}
nincs kis c
Ez a lehetőség természetesen a -wildcard üzemmód mellett is elérhető.
Hasonlóan a ForEach kulcsszóhoz, a switch-nek is van belső változója, melynek $switch a neve, és amelyet felhasználhatunk ciklus-jellegű működés megvalósításra:
[8] PS C:\> $Hosszú = "Vezetéknév: Soós
>> Keresztnév: Tibor
>> e-mail: soostibor@citromail.hu
>> Telefon: 30-3116867
>> Város: Budapest"
>>
[9] PS C:\> $darabok = $Hosszú.Split()
[10] PS C:\> $darabok
Vezetéknév:
Soós
Keresztnév:
Tibor
e-mail:
soostibor@citromail.hu
Telefon:
30-3116867
Város:
Budapest
[12] PS C:\> switch($darabok) {
>> "Vezetéknév:" {[void] $switch.MoveNext(); $vez = $switch.Current}
>> "Keresztnév:" {[void] $switch.MoveNext(); $ker = $switch.Current}
>> "e-mail:" {[void] $switch.MoveNext(); $ema = $switch.Current}
>> "Telefon:" {[void] $switch.MoveNext(); $tel = $switch.Current}
>> "Város:" {[void] $switch.MoveNext(); $var = $switch.Current}
>> }
>>
[13] PS C:\> $ker
Tibor
[14] PS C:\> $vez
Soós
Tehát ez a változó akkor használható igazából, ha egy gyűjteményt adunk át a switch-nek. Ekkor a gyűjtemény egyes tagjait a $switch változó az ő MoveNext() metódusával ciklus-szerűen tudja kezelni. Maga a switch pedig meg tudja vizsgálni az egyes elemeket és a vizsgálat eredményének függvényében különböző kódrészletek futhatnak le.
A fenti példában van egy hosszú sztringem, amiből ki szeretném szedni a nem címke jellegű adatokat, és ezeket be akarom tölteni a megfelelő változókba. Elsőként feldarabolom a sztringet a Split() metódussal. Az így megszülető szavakból álló $darabok tömböt átadom a switch-nek. Ha a switch címkét talál (Vezetéknév:, Keresztnév:, stb.), akkor tovább lép a következő darabra és azt betölti a megfelelő változóba. Így minden adat pont a helyére került.
A switch képes közvetlenül fájlból is felszedni a szövegtömböt, amin aztán soronként a maga ciklusait lefutja. Vigyázni kell azonban ennél a felhasználási módnál, mert itt nincs lehetőségünk a kódolás meghatározására, így ha nem unicode formátumú a szövegfájl, akkor például ékezetes betűkre történő vizsgálat valószínű nem fog helyes eredményt adni.
Én magam sem tudok most hirtelen életszerű példával előállni, mindenesetre ideidézem az about_switch súgó oldalt a switch –file illusztrálására.
switch [-regex|-wildcard|-exact][-casesensitive] -file filename
followed by
{
"string"|number|variable|{ expression } { statementlist }
default { statementlist }
}