Tclコマンド編

 制御系コマンド
 以前にも説明したように、Tclではシンタックスとしてのループ等の制御構造はありません。以下に出てくる制御系コマンドもまさしく「制御を行うコマンド」であり、Tclインタプリタからみれば、1つのコマンドを実行しているだけにしか過ぎません。そのことを踏まえて以下の例題をみてください。
 まず、以下の例題を実行してみてください。
 
proc ctrl_test1 {para1 para2} {
  if { [string compare $para1 $para2] == 1 } {
    puts "1st is greater than 2nd.";
  } elseif { [string compare $para1 $para2] == 0 } {
    puts "1st is equal to 2nd.";
  } {
    puts "1st is less than 2nd.";
  }
}
ctrl_test1 abc ABC
 2つの引数を色々変えて試してください。次は、forとwhileおよびforeachをそれぞれ使って文字列中の特定文字の数を求めるプロシジャです。それぞれのプロシジャは、わざと色々な方法でコーディングしてあります。
 
proc ctrl_test2 {str chr} {
  if { [string length $chr] != 1 } {
    puts "Sorry,2nd PARA is 1BYTE only.";
    return;
  };
  set cnt 0;
  set num [string length $str];
  for {set i 0} {$i<$num} {incr i} {
    if { [string compare [string index $str $i] $chr] == 0 } {
      incr cnt;
    };
  };
  puts "cnt=$cnt";
}
proc ctrl_test3 {str chr} {
  if { [string length $chr] != 1 } {
    puts "Sorry,2nd PARA is 1BYTE only.";
    return;
  };
  set cnt 0;
  set i 0;
  set num [string length $str];
  while {[string length [set j [string index $str $i]]] != 0 } {
    if { [string compare $j $chr] == 0 } {
      incr cnt;
    };
    incr i;
  };
  puts "cnt=$cnt";
}
proc ctrl_test4 {str chr} {
  if { [string length $chr] != 1 } {
    puts "Sorry,2nd PARA is 1BYTE only.";
    return;
  };
  set cnt 0;
  foreach i [split $str {}] {
   if { [string compare $i $chr] == 0 } {
     incr cnt;
   };
  };
  puts "cnt=$cnt";
}
ctrl_test2 tcltktclet t;
ctrl_test3 tcltktclet t;
ctrl_test4 tcltktclet t;
 次の例題では、switchコマンドを取り上げます。C言語のswitch文と考え方は似ていますが、一致条件に文字列や正規表現を使える、1つの条件に合致した場合、それ以下の条件を無視する等の違いがあります。
 引数を、数字のみ、英小文字のみ、英大文字のみ、それ以外のパターンに分けます。
 
proc ctrl_test5 {str} {
  switch -regexp -- $str {
    {^[0-9]*[.]*[0-9]*$} {puts "Numeric Only"}
    {^[a-z]*[.]*[a-z]*$} {puts "Alphabet(small) Only"}
    {^[A-Z]*[.]*[A-Z]*$} {puts "Alphabet(Large) Only"}
    default {puts "Etc."}
  }
}
ctrl_test5 ABCD;
 breakコマンドはループおよび、if コマンド中で、continueコマンドは、ループコマンド中で、それぞれ処理をスキップするために使用します。
 
foreach i {0 1 2 3 4 5} {
  if { [string compare $i 4] == 0 } {
    continue;
  };
  puts $i;
}
foreach i {0 1 2 3 4 5} {
  if { [string compare $i 4] == 0 } {
    break;
  };
  puts $i;
}

 

  if 条件によるスクリプト実行。
if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else? ?bodyN?
expr1 条件式。評価結果0が偽でそれ以外は真。
?then? キーワード。無くても可。
body1 条件式が真の時実行する処理。
elseif expr1が偽の時、評価する条件式。
例) >set elm "abc"
>if { $abc == "ab" } {
puts "pat-1"
} elseif { $abc == "bc" } {
puts "pat-2"
} {
puts "pat-3"
}
pat-3
文字列作成。
文字列を評価する。
「ab」ならpat-1

「bc」ならpat-2

それ以外ならpat-3を表示する。
  while 条件式が真のあいだスクリプトを繰り返し実行する。
while test body
test 条件式評価。正しい真偽値であること。
body ループ処理するスクリプト。処理終了後、
再度条件式を評価します。
例) >set cnt 0
>while {$cnt<10} {
lappend lst $cnt
incr cnt
}
初期値0を設定。
10未満なら処理を繰り返す。
変数「lst」にリスト要素として追加。
ループ中に条件値が変わらないと無限ループになる。
  for C言語の「for」ライクなループ。
for start test next body
start 初期化。ループ開始時に1回のみ実行される。
test 条件式評価。
next ループ処理ごとの最後に実行する処理。
これを実行後に条件式評価が再度行われる。
body ループ処理するスクリプト。
例) >for {set cnt 0} {$cnt<10} {incr cnt} {
lappend lst $cnt
}
上記のwhileコマンドと同じ処理。
  switch 指定文字列のマッチングによって処理スクリプトを1つ選択して実行する。
switch ?options? string pattern body ?pattern body ...? :形式1
switch ?options? string {pattern body ?pattern body ...?}:形式2
形式1は、patternがその場で評価されるので変数使用時に便利。
ただし、見栄えのために改行する際は、¥を忘れずにつけること。
?options? マッチング方式の指定。以下の通りがある。
-exact  完全一致。デフォルト。
-glob   *などのワイルドカード指定する。
-regexp 正規表現を指定する。
--    オプションの終了。これ以降はハイフン付き文字列
      も次のstringとして認識する。
string マッチング対象文字列。
pattern マッチングパターン。
body マッチングした場合の処理。
例) >  
  break 最も内側のループ処理を抜ける。
break
例) >set a 1
>while {$a<5} {
set cnt 0
while { $cnt < 3 } {
puts "$a,$cnt"
incr cnt
break
}
incr a
}
1,0
2,0
3,0
4,0
外側のループの初期値を設定。
外側のループ
内側のループの初期値を設定。
内側のループ
最初のループ処理
内側のループのカウンタ加算
無条件にbreak

外側のループのカウンタ加算

結果。


  continue ループ処理をスキップする。
continue
例) >set lst {0 1 2 {} 4 5}
>foreach i $lst {
if { [string length $i] == 0 } {continue}
puts $i
}
0
1
2
4
5
6個の要素からなるリストを設定。
ループ処理。
要素の長さが0ならスキップ。
要素を表示。

結果。



  foreach リストから要素を取り出して変数に設定しながらループ。
foreach varname list body :形式1
foreach varlist1 list1 ?varlist2 list2 ...? body:形式2
varname
varlist1
要素を設定する変数名。リストも可。リストの場合、対応する個数分ずつリストから
取り出される
list
list1
リスト。形式2の場合、変数名(リスト)とリストの組を複数記述可能。
body ループ処理。
例) >set lst1 {1 2 3}
>set lst2 {Jan Feb Mar}
>foreach i $lst1 j $lst2 {
puts "$i : $j"
}
1 : Jan
2 : Feb
3 : Mar
>set lst3 {1 Jan 2 Feb 3 Mar}
>foreach {i j} $lst3 {
puts "$i : $j"
}
1 : Jan
2 : Feb
3 : Mar


2つのリストでループ。


結果。



1つのリストから2個ずつ取り出してループ。


結果は同じ。