switch制御構文

前回は条件に応じて処理を分岐させる機能としてif制御構文を取り上げた。if制御構文を利用することで複数の条件で処理を分岐させることができることも示した。今回はこれと同じような処理を行う方法としてswitch制御構文を取り上げる。

if制御構文もswitch制御構文も行う内容は同じだが、書き方が異なっている。switch制御構文は特に複数に分岐させる場合に読みやすくなると考えられている。

文法的にはswitch制御構文は次のように記述する。

switch制御構文の基本的な使い方その1

switch [-regex|-wildcard|-exact][-casesensitive] (<value>)
{
    "string"|number|variable|{ expression } { statementlist }
    default { statementlist }
}

switch制御構文の基本的な使い方その2

switch [-regex|-wildcard|-exact][-casesensitive] -file filename
{
    "string"|number|variable|{ expression } { statementlist }
    default { statementlist }
}

ちょっとこれではわかりにくいと思うので、実際の例を取り上げながらswitch制御構文の使い方を紹介しよう。

switch制御構文の使い方

switch制御構文では、次のようにswitch (値)の値の部分が分岐の対象となり、そのあとに続く値1、値2、値3… のどれに一致するかで処理が切り分けられる。defaultはif制御構文におけるelseに近い意味を持っており、以下の書き方の場合にはif制御構文のelseと同じ意味として機能する。

switch制御構文の使い方その1

Switch (値)
{
    値1 {処理1; Break}
    値2 {処理2; Break}
    値3 {処理3; Break}
    default {処理4}
}

Breakの指定はオプショナルなので、次のように書くこともできる。ただし、上と下の書き方では意味が異なり、処理のフローも違うことに注意する必要がある。

switch制御構文の使い方その2

Switch (値)
{
    値1 {処理1}
    値2 {処理2}
    値3 {処理3}
    default {処理4}
}

defaultもオプショナルなので、次のように書くこともできる。

switch制御構文の使い方その3

Switch (値)
{
    値1 {処理1}
    値2 {処理2}
    値3 {処理3}
}

if制御構文のelseが1回しか使えなかったように、switch制御構文でもdefaultは1回までしか使うことができない。defaultはどの条件でも一致するという意味の指定になっている。

次に実際の実行例を見ながら、それぞれどのように機能するのか追ってみよう。

まず、次の例だ。これはもっとも簡単なswitch制御構文の使い方となる。一致するものがあればそれが実行され、一致しなければdefaultが実行されていることがわかる。

一致した処理が実行されている

PS /Users/daichi> $val = 2
PS /Users/daichi> switch ($val)
>> {
>>     1 {"1"}
>>     2 {"2"}
>>     3 {"3"}
>>     4 {"4"}
>>     default {"そのほか"}
>> }
2
PS /Users/daichi>

一致しないためdefaultが実行されている

PS /Users/daichi> $val = 10
PS /Users/daichi> switch ($val)
>> {
>>     1 {"1"}
>>     2 {"2"}
>>     3 {"3"}
>>     4 {"4"}
>>     default {"そのほか"}
>> }
そのほか
PS /Users/daichi>

switch制御構文では、Breakを指定しない限り複数の条件に一致することができる。

たとえば次のように実行した場合、一致するすべての条件が実行されている。これがif制御構文とswitch制御構文の大きな違いだ。Breakを指定しなければ次の条件を見に行って一致していれば実行する。if制御構文にはない機能だ。

switch制御構文では複数の条件に一致させることができる

PS /Users/daichi> $val = 2
PS /Users/daichi> switch ($val)
>> {
>>     1 {"1"}
>>     2 {"2"}
>>     3 {"3"}
>>     4 {"4"}
>>     1 {"一"}
>>     2 {"二"}
>>     3 {"三"}
>>     4 {"四"}
>>     default {"そのほか"}
>> }
2
二
PS /Users/daichi>

これを避け、1度でも一致した場合にはそこで処理を終えたいという場合、次のように処理の最後にBreakを指定するようにする。

処理の終端にBreakを指定すればそれ以上条件一致は行われない

PS /Users/daichi> $val = 2
PS /Users/daichi> switch ($val)
>> {
>>     1 {"1"; Break}
>>     2 {"2"; Break}
>>     3 {"3"; Break}
>>     4 {"4"; Break}
>>     1 {"一"; Break}
>>     2 {"二"; Break}
>>     3 {"三"; Break}
>>     4 {"四"; Break}
>>     default {"そのほか"}
>> }
2
PS /Users/daichi>

これはPowerShell Coreに限らず、ほかのプログラミング言語にもよく見られる動作だ。switch制御構文に類似する機構では、このように処理の終端を指定しないかぎり、次の条件一致へ進んでいくといった実装になっていることが多い。

switch制御構文のパラメータ

最初に示した基本的な使い方でswitch制御構文にはパラメータが指定できることに気がついたと思う。これは(値)の部分をどのように一致させるかという動作などを指定するもので、それぞれ次のような意味になっている。

パラメータ 内容
-Wildcard 値が文字列だった場合に、文字列をワイルドカード文字列として一致させる
-Exact 値が文字列だった場合に、文字列に完全一致する場合のみ一致させる
-CaseSensitive 値が文字列だった場合に、大文字と小文字を区別して一致させる
-Regex 値が文字列だった場合に、正規表現として一致させる
-File 値を指定したファイルから入力する

たとえば文字列にワイルドカードを含めて一致させようとしても、パラメータを指定しないと動作しない。次の実行例では「二個」と「二」が一致して欲しいという意図が読み取れるものの、指定がないと「二個」と「二」は文字列として比較されるので一致されないことになる。

-Wildcardパラメータを指定しないとワイルドカードとしては比較されない

PS /Users/daichi> $val = "二個"
PS /Users/daichi> switch ($val)
>> {
>>     "一*" {"一"}
>>     "二*" {"二"}
>>     "三*" {"三"}
>>     "四*" {"四"}
>>     default {"そのほか"}
>> }
そのほか
PS /Users/daichi>

この処理に対して-Wildcardパラメータを指定すると次のようになる。*がワイルドカードとして処理されるようになり、意図通りの一致が機能していることがわかる。

-Wildcardパラメータを指定するとワイルドカードが機能するようになる

PS /Users/daichi> $val = "二個"
PS /Users/daichi> switch -Wildcard ($val)
>> {
>>     "一*" {"一"}
>>     "二*" {"二"}
>>     "三*" {"三"}
>>     "四*" {"四"}
>>     default {"そのほか"}
>> }
二
PS /Users/daichi>

パラメータ-Regexを使えば正規表現を利用することができる。

-Regexで正規表現による一致処理

PS /Users/daichi> $val = "https://news.mynavi.jp/"
PS /Users/daichi> switch -Regex ($val)
>> {
>>     'http[s]?\://.*' { "$_ : HTTPまたはHTTPS";    Break }
>>     'ftp\://.*'      { "$_ : FTP";                Break }
>>     '\w+@\w+'        { "$_ : 電子メールアドレス"; Break }
>>     default          {"そのほか"}
>> }
https://news.mynavi.jp/ : HTTPまたはHTTPS
PS /Users/daichi>

if制御構文を使うべきかswitch制御構文を使うべきかは好みが出てくるところだ。基本的にはコーディング中にこちらの方が理解しやすいと思った方を使ってもらえればと思う。どちらも書けるようにしておこう。

参考資料