コマンドラインと特殊文字

Tclには文法と呼ぶほどのものはありません。 Tclスクリプト構造はTclリスト構造そのものです。 ここでの解説は「TclリストをスクリプトとしてTclパーサーに与えるとどのように解釈してくれるのか」 について解説するものであり、それは「Tclリスト構造及び特殊文字の役割」の解説です。

コマンドライン

コマンドとアーギュメントのセットがTclスクリプトの最小構成単位です。
下記の例ではsetがコマンドでvalと1がアーギュメントです。

set val 1

アーギュメントをひとつも必要としないコマンドも当然許されます。
以降、コマンドとアーギュメントのセットをコマンドラインと呼びます。

ブランクとタブコードの機能(アーギュメント区切り)

コマンドラインはリストであり、その中のコマンドやアーギュメントはリストの要素です。 これらのリスト内要素の区切りコードはブランクまたはタブコードです。 連続したブランクやタブはひとつの区切りとして扱われます。
Cをはじめ、他のプログラミング言語はブランクやタブを無視しますが、Tclでは重要な役割を果たすことに注意してください。

改行コードとセミコロン文字の機能(コマンドライン区切り)

コマンドラインの終端は改行コードかセミコロン文字です。 セミコロン文字は、下記のように、コマンドラインを一行の中に複数記述したい場合に用います。

set a 100; set b 200; set c 300

(コメント行もコマンドラインのひとつです。 #がコメントコマンドであり、改行かセミコロンまでコメント文字とみなされます。)

セミコロンや改行コードはコマンドラインの末尾に必ず現れますが、セミコロンや改行コードが必ずコマンドラインの終端になる訳ではありません。 リスト構造の仕様からすると、セミコロンも改行コードも単なる文字です。 その例が、ひとつのコマンドラインが複数行に渡って記述されているケースです。 後ほど解説される ”、[、{ のような特殊記号が現れると、Tclパーサーはそれらの対の記号が現れて閉じられるまで(リストの終端が現れるまで)、行を跨がっていても追跡してくれます。

ダブルコーテーション引用符の機能(文字列)

ブランク、タブ、改行コードを含んだアーギュメントをコマンドに渡すには””で挟みます。

set address "東京都 町田市 南成瀬"

下記の例では改行コードも含んだ文字列がコマンドに渡されます。 ””が閉じないうちに現れた改行コードはコマンドライン終端コードにはなりません。

set 景品 "
一等賞 自動車
二等賞 ふりかけ
"

また、”はアーギュメントの先頭に記述されている場合にのみ、上述の機能が働きます。 下記の例では、2つの”は文字としてコマンドにそのまま渡されます。 アーギュメント文字列の途中にあるからです。

set val aaaa"bbbb"

尚、後述の置換子は””内にあっても全て働きます。

$文字の機能(変数置換)

$文字は変数置換子です。
$が先頭に付いた文字列は変数とみなされ、値に置換されてからコマンドに渡されます。
例えば、下例のコマンドラインがTclパーサーに渡されると、bは変数とみなされて、bの値が100であれば、setコマンドに渡されるアーギュメントはaと100になります。

set a $b

この置換は1回しか行われません。bの置換結果が$cであったとしても、cの再置換は試まれずに$cの2文字がsetコマンドに渡されます。 Tclパーサーがコマンドにアーギュメントを渡す時の変数置換は一回だけ、ということです。
$文字が文字列の途中にあっても変数置換機能は働きます。

ブランケット引用符 [ ]の機能(コマンド置換)

[ ]引用符はコマンド置換子です。
[ ]で挟まれたリストはコマンドラインとみなされ、その実行結果がひとつのアーギュメントとしてコマンドに渡されます。

下記のコマンドラインがTclパーサーに渡されると、[ ]ではさまれたコマンドラインの計算結果20030がsetコマンドに渡されます。

set a [expr 100 * 200 + 30]

下記の様に、文字列中のいかなる位置にあってもコマンド置換機能は働きます。

puts "価格=[expr 10 * 4]円"

また、[ ]内に改行コードが含まれることも許されます。 [ ]が閉じないうちに現れた改行コードはコマンドライン終端コードではなく要素区切りコードとして扱われます。

[ ]はネスト(入れ子構造)も許されます。 set subfolder [file tail [file dirname $file]]

\文字の機能(バックスラッシュシーケンス)

\文字はC/C++と同等のバックスラッシュシーケンス機能を持ちます。
例えば改行コードは \n 、水平タブコードは\tと記述できます。

これまで説明してきた置換子の前に\を付けるとそれらは単なる文字として扱われます。 set msg "\$をつけると変数置換が行われます"
set msg "\[と\]で挟むとコマンド置換が行われます。"

下記の2行は等価です。 set address "東京都 町田市 南成瀬"
set address 東京都\ 町田市\ 南成瀬

文字コードも下記のように\xに続けた16進数で記述できます。 set esc \x1b

ブレース引用符{ }の機能(置換抑制)

アーギュメントの前後に記述された{ }引用符は、中に含まれるあらゆる特殊文字の機能(置換機能)を無効化し、すべて単なる文字としてコマンドにそのまま渡します。 ¥文字もそのまま渡されます。改行コードも単なる文字コードとして扱われます。

set a {[set b $c]}

上記のコマンドラインがTclパーサーに渡されると、{ }ではさまれた文字列がそのままsetコマンドにひとつのアーギュメントとして渡されます。それぞれ [ ] $ 文字の特殊機能が奪われますので、コマンド置換も変数置換も行われないのです。

また、{ }はアーギュメントの先頭と末尾に記述されている場合にのみ、上述の機能が働きます。 これはダブルコーテーション引用符と同じ性質です。
下記の例では、{ } は文字としてコマンドにそのまま渡されます。

set val aaaa{bbbb}

プログラミング言語では、代入式や数値演算式などの式が言語仕様の中に組み込まれています。Tclにも式はありますが、これはTclが言語として提供しているものではなく、exprやifコマンドが提供しているものです。つまり式をアーギュメントとして受け付けるコマンドにのみC言語相当の数値演算式、論理演算式、関係演算式を記述することができます。

set a [expr $b * sin($c)]

ifコマンドに与える条件式では、文字列比較も数値比較と同じように記述できます。

if {($a/2)>10 && $b=="tokyo"} {......

式のなかのブランクは無視されます。

演算子には算術演算子(-,!,*,/,%,+,-)・比較演算子(<,>,<=,>=,==,!=)・論理演算子(&&,||)・ビット演算子(&,|,^,<<,>>,~)・条件演算子((条件式)? a:b)があり、C言語と同機能です。

オペランドには整数や実数、及び数学関数を与えることができます。 数字関数はANSI/Cライブラリ関数が提供されています。 expr 2*sin($x)
expr hypot($x2-$x1,$y2-$y1) + $z

式を受け付けるコマンドはTclパーサーの助けをあまり必要としません。変数置換機能を自分自身に持っています。 従って、式を変数置換を抑制する{ }で挟んでも同じ結果が得られます。むしろ{ }で挟んだ方が効率的です。 expr {2*sin($x)}

定数

Tclパーサーは型を扱いませんが、実際のスクリプトでは16進数整定数なども記述できます。 例えば、数値演算を行うexprコマンドの式に0xffのような16進数の数値を与えることができます。
Tclパーサーは"0xff"という文字列をexprコマンドに渡すだけですが、コマンドがこれを16進数と解釈するのです。

(exprコマンドやifコマンドは、先頭の文字が0の整数は8進数、0xならば16進数として解釈します。 指数形式の実数も指定可能です。 整数のみならば演算も結果も整数で求められます。 実数が含まれていれば実数で返されます。まとめると、式はC言語と同等の機能を持つので定数についても然り、ということです。)

変数の型

定数と同様に、Tclパーサーが扱う変数にintegerやdoubleなどの型はありませんが、 配列変数とそうでない変数との区別があります。
例えば下記の2行目はエラーになります。配列と認識された変数aを2行目では一般変数として扱ったからです。 set a(0) 100
set a 200

文字列変数とリスト変数の区別はありませんが、内部では構造が異なる為、リスト変数にはリストコマンドでアクセスする習慣をつけるべきです。
例えばリストをセットする1行目と2行目は同じ結果を得られますが2行目のように記述すべきです。 set rank "松 竹 梅"
set rank [list 松 竹 梅]

変数の名前

変数名には漢字も含めて全ての文字が使えます。
ただし$置換子によって置換されるとき、その名前に特殊文字が含まれていると、その前までが変数名として認識されてしまい、思わぬエラーが発生します。
例えば abc.def 変数への値セットは成功しますが、$abc.def として参照しようとすると $abc の置換になってしまいます。
このような場合には、変数名を { }引用符で囲みます。 puts ${abc.def} なお、FreeSoftNet拡張のTclは変数名に漢字を使っても引用符で囲む必要はありませんが、純正Tclでは囲む必要があります。

変数のスコープと寿命

変数の型はコマンドに預けていますが、変数のスコープや変数の寿命はTclパーサーが管理しています。
変数のスコープにはグローバル変数、ローカル変数、名前空間変数がサポートされています。
ローカル変数はプロシージャ(後述)内に作成され、終了すると自動的に削除されます。
グローバル変数は、変数にアクセスする前にglobalコマンドで宣言しておかなければなりません。
名前空間変数は、変数にアクセスする前にvariableコマンドで宣言しておかなければなりません。

実際にメモリに作成されるのは、宣言された時ではなく、初めて値がセットされた時です。
したがって、値が設定されていない変数を参照するバグはありえません。エラーとして検出されます。

全ての変数をunsetコマンドによって削除することが可能です。
これはTclの大きな特長です。すべての変数がダイナミックに生成、削除できるオブジェクトになっています。

配列変数

配列変数は変数名に( )が付いている変数です。例えばabc(1)などの変数です。
ただし、配列変数としての宣言や要素数を指定するコマンドはありません。 ( )が付いた変数に値がセットされるときに配列変数として認識・登録されます。
同じ名前の配列変数と通常変数を同時に存在させることはできません。 例えば set abc 1 を実行した後に set abc(1) 1 を実行するとエラーになります。この逆も然りです。 つまり早いモノ勝ちです。
配列変数の要素には文字列も使用できます。 またカンマ(,)やピリオド(.)などで要素を区切れば多次元配列になります。

set abc(a.b) 100
set abc(a.c) 200

set index c
puts $abc(a.$index)→200が表示

要素数は自動拡張です。
配列オーバーは最も陥りやすいバグですが、Tclではあり得ません。

また、配列の要素をリストとして抽出したり、要素と値が繰り返されるリストから配列変数を作成するコマンドが提供されています。

下記の例では
  人口密度(東京) ←100
  人口密度(埼玉) ←60
  人口密度(群馬) ←30
の配列作成と値のセットを行い、その後に配列の要素をリストとして表示しています。

array set 人口密度 {
     東京 100
     埼玉 60
     群馬 30
  }
puts [array names 人口密度] →"東京 埼玉 群馬"が表示される。

array setコマンドは、ダイナミックな構造体変数のような使い勝手を提供してくれます。

配列変数をグローバル変数として宣言したり削除するには変数名だけを与えます。

global 人口密度
unset 人口密度

リスト変数とリスト処理

Tclの特長にリスト処理があります。
リスト処理とは複数のデータの集まりを、あたかもひとつのデータのように処理することです。
リストデータが格納された変数をリスト変数と呼んだりしますが、リスト変数というものが他の変数と区別されて存在しているわけではありません。
この点が配列変数とは異なります。
リスト構造のデータが格納された変数を単にリスト変数と呼んでいます。

Tclのリストコマンドが扱うリストは極めてシンプルな構造です。
要素がブランク、タブコード、改行コードのいずれかで区切られてひとつの文字列になっている構造です。
ブランクやタブを含む要素は{ }引用符で囲まれています。

AAAA BBB {CCCC DDDD} EEEE

上記のリストには4つの要素があることになります。
また{ }引用符はリストを入れ子構造にするものであるとも言えます。
上の例で、3番目の要素を取り出すと CCCC DDDD が得られますが、この要素は更に2つの要素から成るリストとして扱うことができます。

実際にリストを扱う際には、上述の構造を意識する必要はありません。
リストを作成したり要素を抽出したりするリストコマンドが提供されています。

アーギュメントを要素としたリストを生成する
set LIST [list AAAA BBBB "CCCC DDDD" EEE]
リストからi番目の要素を取り出す
set Element [lindex $LIST $i]
リストの要素を順に変数elemに取り出してのループ処理
  foreach elem $LIST {
    puts $elem
  }

リスト処理はCSV形式のデータを処理する場合などに重宝します。
また、SQL命令でデータベースから表データを抽出しての処理なども、簡潔かつ汎用的に記述することができます。


プロシージャ

プロシージャはTclスクリプトで作成されたコマンドのことです。 すでにTclに組み込まれているコマンドと同じように使えます。
プロシージャはprocコマンドで作成します。

proc プロシ−ジャ名 変数リスト Tclスクリプト

proc cal { a b c } {
     return [expr ($a+$b)*$c]
}

値を返す場合はreturnコマンドを用います。
returnコマンドが書かれていなければ、最後に実行したコマンドの戻り値がプロシージャの戻り値になります。
利用方法
set val [cal 10 20 300]

変数のアドレス渡し(upvar)

アーギュメントに変数名を与え、プロシージャがその変数に値をセットする方式(アドレス渡し)も用意されています。
プロシージャ内ではアーギュメントに渡されてきた変数名をupvarコマンドで内部変数にリンクさせてからアクセスするようにします。

proc cal {a b c answer} {
     upvar $answer ans
     set ans [expr ($a+$b)*$c]
}
利用方法
cal 10 20 300 result
puts "答えは$result"

アーギュメントに渡す変数はあらかじめ存在していなくてもかまいません。
upvarコマンドが(呼び出し側に)作成してくれます。

リストコマンド

リスト処理とは、いくつもの値が1つに取りまとめられ、その集まりを1つの値として取り扱う処理です。
リストは特定の構造をもった文字列として表現されており、そのリストを生成したり、要素の挿入,削除,検索,置換などを行うのがリストコマンド群です。

斜体は省略可能なアーギュメント。...は複数指定可能を示します。

concat $list...

リストを結合して新しいリストを返す。

lappend varName $val...

変数varNameに要素$val...を追加し結果のリストを返す。

lindex $list $index

リスト$listから$index番目の要素を取り出して返す。$indexは0から。

linsert $list $index $val

リスト$listの$index番目の要素の前に全ての要素$val...を挿入したリストを返す。

list $val...

すべての要素$val...を要素としたリストを返す(生成)。

llength $list

リスト$listの要素数を返す

lrange $list $first $last

リスト$listの$first番目から$last番目までの連続要素をリストとして返す。
$lastに文字列endを与えると最後の要素までの指定となる。
先頭が0である。

lreplace $list $first $last $val...

リスト$listの$first番目から$lastまでの連続要素をすべての要素$valで
置きかえ、新しいリストを返す。

lsearch $switch $list $pattern

リスト$listから、$switchであたえられたパターンマッチング方式で、$patternに合致する最初の要素の順番を返す。
マッチング方式は-glob -exact -regexpの3種で、-globがデフォルト。
 -exactは完全一致。
 -regexpは正規表現規則。
 -globはglob方式。

※glob,正規表現の解説はパターンマッチングを参照してください。

lsort $switch -command $com $direction $list

リスト$listの要素をソートしたリストを返す。
$switchは-integer(整数) -ascii(文字) -real(実数)の3種。 -asciiがデフォルト。
$directionは方向スイッチで、-decreasingを指定すると降順となる。

join $list $joinstring

リスト$listの要素を$joinStringで結合した文字列を返す。
$joinStringのデフォルトはスペース。

split $string $splitChars

文字列$stringを、$splitCharsで区切られた文字列を要素としたリストを返す。
$splitCharsのデフォルトはブランク。
このコマンドは、joinコマンドと逆の関係にある。

実行例

Tclsh.exeで実際に実行してみてください。

set List [list bb aa cc {} dd ee]

bb aa cc {} dd ee

llength $List

6

lrange $List 2 end

cc {} dd ee

lsearch $List cc

2

lindex $List 4

dd

lappend List ff gg

bb aa cc {} dd ee ff gg

linsert $List 2 xx yy

bb aa xx yy cc {} dd ee ff gg

lsort $List

{} aa bb cc dd ee ff gg

lreplace $List 1 xx yy

bb xx yy cc {} dd ee ff

join $List -

bb-aa-cc--dd-ee-ee-gg

split "aa\tbb\tcc\t\tdd" \t

aa bb cc {} dd

制御コマンド

制御コマンドは「言語」に組み込まれているものではなく、それぞれコマンドとしてあらかじめ実装されているものに過ぎません。従って、自分の制御コマンドを作成することも可能です。制御コマンドも作成できるところは、他のプログラム言語、スクリプト言語には見られないTclの大きな特長です。

if {test1} {body1} elseif {test2} {body2} elseif..... else {bodyn}

test1:body1(Tclスクリプト)を実行する条件式。真ならbody1が実行される
test2:test1の条件が偽のとき評価される条件式。
真ならbody2(Tclスクリプト)が実行される
bodyn:すべての条件が偽のとき実行されるTclスクリプト

for {init} {test} {reinit} {body}

init:初期設定Tclスクリプト
test :ループ条件式(真ならループ継続)
reinit:再設定Tclスクリプト
body:Tclスクリプト(処理本体)

while {test} {body}

test:条件式(真ならループ継続)
body:Tclスクリプト(処理本体)

switch $switch $string {$pattern1 {body} ..... $pattern {body}}

stringを検査し、合致したpatternのbody(Tclスクリプト)を実行する。
switchはパターンマッチング方式の指定であり -glob -exact -regexpの3種がある。
デフォルトは -glob

foreach $valNameList $list {body}

リストlistから要素を取り出して変数valNameListに順に代入後、bodyを実行。
この処理をlistの先頭要素から最後の要素まで繰り返す。

break

ループ脱出。for while switch foreachのbodyに記述可

continue

ループの条件式評価にジャンプ。for while foreachのbodyに記述可

source $sourceFileName

Tclスクリプトファイル$sourceFileNameをオープンし内容を実行後、結果を返す。

eval arg1 arg2...

すべてのアーギュメントをスペースを挟んで結合したあと、その文字列をTclスクリプトとして実行し結果を返す。
コマンドをダイナミックに作成して実行する場合に使用する。

文字列操作コマンド

format $formatString $val ...

$formatStringはANSII Cに準拠した変換指定子。
変換指定子の順に、その数だけ値$valを与える。変換結果が返される。

scan $string $formatString varName...

$formatStringの指定に基づいて$stringを解析し変換指定子ごとに値をvarNameに代入する。
正しく変換された数が返される。

regexp $switches $exp $string varName...

正規表現$expが$stringに合致するか否か調べ、合致すれば1を、しなければ0を返す。
変数名varNameが与えられていれば合致した文字をセットする。
$switchesに-nocaseを指定すると大文字小文字の区別が無視される。
-indicesを指定すると変数にセットされるのは合致した部分文字列のインデックスリスト(例"5 8")になる。

regsub $switches $exp $string $change varName

正規表現$expが$stringに合致するか否か調べ、合致する部分を$changeに置き換え、その結果の文字列を変数varNameにセットする。
$switchesに-nocaseを与えると大文字小文字の違いを無視する。
また-allを与えると$stringの中の合致文字置換はすべてに対して行われる。-allを指定しないと合致した最初の文字列だけの置換となる。

string compare $string1 $string2

$string1と$string2を辞書順で調べ、1が2より小さい、等しい、大きいの順で-1,0,1を返す

string first $string1 $string2

$string2の中で最初に$string1に合致した部分文字列の先頭インデックスを返す。

string last $string1 $string2

$string2の中で最後に$string1に合致した部分文字列の先頭インデックスを返す。

string index $string1 $index

$stringの中から$index番目の文字を返す。
範囲外なら空文字を返す。

string length $string

$stringの文字数を返す。バイト長ではなく文字数を返すので漢字文字数を得ることができる。バイト長は string bytelength で求めることができる。

string match $pattern $string

glob形式のマッチング規則で、$pattenが$stringに合致していれば1を、不合致なら0を返す。

string range $string $first $last

$stringの$firstから$last番目までの文字列を返す。

string tolower $string

$stringを小文字変換して返す。

string toupper $string

$stringを大文字変換して返す。

string trim $string $removeChars

$stringの両脇にある$removeCharsを取り除いた文字列を返す。

string trimleft $string $removeChars

string trimと同じだが先頭文字だけが切り捨てられる。

string trimright $string $removeChars

string trimと同じだが末尾文字だけが切り捨てられる。

実行例

Tclsh.exeで実際に実行してみてください。

set txt AABBCCDDEEFFGGHHAA

AABBCCDDEEFFGGHHAA

string length $txt

18

string index $txt 2

B

string range $txt 0 5

AABBCC

string range $txt 6 end

DDEEFFGGHHAA

string trim $txt A

BBCCDDEEFFGGHH

string trimleft $txt A

BBCCDDEEFFGGHHAA

string trimright $txt A

AABBCCDDEEFFGGHH

string tolower $txt

aabbccddeeffgghhaa

string compare $txt AABB

1

string first CCD $txt

4

string last AA $txt

16

regexp B* $txt

1

regsub -all AA $txt ZZZ newtxt

ZZZBBCCDDEEFFGGHHZZZ

format “%6.6s” $txt

AABBCC

パターンマッチング(globと正規表現)

regexp,regsub,string match,switchコマンドなどが文字列を比較するとき、その比較方法(パターンマッチング)にglob形式や正規表現が用いられます。

glob型式

glob形式とは、OSにファイル名を指定するときに用いられる馴染みの深い方法です(DIR *.dat など)。glob形式では次の特殊文字が使えます。

*

任意の長さ(ゼロを含む)の文字列

?

任意の1文字

[chars]

charsのなかのいずれか1文字 [a-d]という指定は [abcd]と同

特殊記号の前につけ、単なる文字としての扱いを指定

123ABC* の文字列に対するマッチング結果

*ABC  
ABC* 
??????? 
?????? 
???A?C? 
????A?C 
??????\* 
[0-9]* 
[A-Z]* 
*[A-Z]* 
*[D-Z]* 
?2??B?? 

正規表現

glob形式の弱点は「文字列が数字のみから構成されているか」というような指定ができないことです。
[0-9]はひとつの文字に対する評価であり、もし3桁の数字か否かを評価するには[0-9][0-9][0-9]と指定しなければならず、とても冗長です。しかも桁数の指定も伴ってしまいます。

これに対し、正規表現は強力です。
[0-9]+ と指定するだけで、桁数を問わず数字のみで構成されている文字列か否かを判定できます。
+は「直前の文字の1つ以上の繰り返し」という意味を持ちます。

正規表現では下記の特殊文字が使えます。

.

任意の1文字

^

文字列の先頭
ただし[chars]書式のcharsの先頭につけられるとNOTの意味をもつ

$

文字列の終わり

[chars]

charsのなかのいずれか1文字 [a-d]という指定は [abcd]と同
charsの先頭が]の場合は]は文字として扱われる。
charsの先頭または末尾の-は文字として扱われる。

*

直前の要素の0回以上の繰り返し

+

直前の要素の1回以上の繰り返し

?

直前の要素があってもなくても可

( )

グループ化、及び部分文字列として抽出する範囲

|

OR

特殊記号の前につけ、単なる文字としての扱いを指定


正規表現は文字ひとつひとつについて指定していきます。それらを要素と呼びます。
要素は文字か[ ]で与えられる文字範囲です。
それらの要素を( )で挟んでグループ化すると、ひとつの要素として扱われます。

要素の繰り返しを * +で指定できます。
?はその要素がない場合も可とするものです。
*+?を演算子と考え、( )でグループ化できることを考えると、正規表現は多項式の構造をもっており、文字列の構造式と呼べるものであることがわかります。

16進数として正しく記述されている文字列か否かを判定する正規表現を考えてみます。

まず「先頭に0xが付いていてもいなくても可とする」は ^(0x)? と表現されます。
( )で挟んで要素0とxをグループ化し0xの文字列を生成しています。
^は文字列の先頭(0xの前に文字はない)を表しています。
?は直前の要素―即ち0xがあってもなくても良いことを表しています。

つぎに「16進数に使える文字」を指定します。
それは[0-9a-fA-F]と表現されます。
そしてこれらの文字が繰り返して現れるのであるから+を付けて [0-9a-fA-F]+ となります。
これらの文字だけが連続したあと「文字列は終了する」ことを表す$を末尾につけて、最終的に下記の正規表現となります。

^(0x)?[0-9a-fA-F]+$

これをregexpコマンドに与えて文字列を評価すると下記の例となります。 

regexp {^(0x)?[0-9a-fA-F]+$} 0x25AF

1

regexp {^(0x)?[0-9a-fA-F]+$} 25af

1 (正規表現の?が+なら0が返ります)

regexp {^(0x)?[0-9a-fA-F]+$} 25aG

0 (正規表現に$がなければ1が返ります)

regexp {^(0x)?[0-9a-fA-F]+$} 0x

0 (正規表現の+が?なら1が返ります)


正規表現をアーギュメントにして渡す時は必ず{ } ではさんで下さい。
正規表現の特殊文字がTclの特殊記号と重複しているからです。
正規表現は、その解釈のアルゴリズムを考えるともっと理解が深まります。

正規表現によるパターンマッチングは次のように処理されます。
まず正規表現の最初の要素を取り出します。
その要素で文字列の先頭文字を評価します。
合致していなければ次の文字を調べ、これを合致するまで繰り返します。
合致する文字が現れたら次の正規表現要素を取り出します。
その要素が+記号だったら前回の要素で、次の文字を評価します。
これも合致していれば次の文字を評価し、合致しない文字が現れるまでこれを繰り返します。
+記号はそのような処理を要求するものです。
合致しない文字が現れたら、次の正規表現要素を取り出してその文字を評価します。
このような手順で評価をすすめ、全要素について評価がすめば最終判断として合致(1)を返します。

正規表現要素の全てについての評価が完了しない限り、判定は下されません(regexpコマンドは終了しません)。 不一致の文字が見つかればすぐに0を返して終了しそうですが、決してそうではありません。 途中で不一致判定が成されても、後続に'|'記号があれば再評価が必要だからです。

正規表現は複雑な文字列評価を1行でプログラミングできますのでとても強力です。単に合致、不一致の判定だけではなく、文字列の特定部分を変数に抽出することなどもできます。regexpコマンドの第3アーギュメントに変数名を与えると、合致した文字列をその変数に代入してくれますし、更に変数を与えると、正規表現中の()で挟まれた部分に合致する文字列を順に変数にセットしてくれもします。

regexp {[0-9]+} "定価120円" price
regexp {定価([0-9]+)円} "定価120円" match price

ファイル操作コマンド

cd $dirName

作業ディレクトリィを変更する。

open $fileName $access

ファイルを開きファイル識別子を返す。
$accessはr,r+,w,w+,a,a+のいずれか。
デフォルトはr。

close $fileID

ファイルを閉じる。

puts $option $fileID $string

文字列$stringを識別子$fileIdのファイルに書く。
$fileIdを省略するとstdoutに出力される。
$optionに-nonewlineを指定しないと改行コードが書かれる。

gets $fileID verName

識別子$fileIdのファイルから文字列を読み込み、変数varNameに代入しその文字数を返す。
ファイル末尾に達した場合は-1を返す。
変数名が省略されると文字列を返す。
末尾に達した場合は空文字を返す。

read $option $fileID

識別子$fileIdのファイルから残りのデータをすべて読み込み、それらを返す。
-nonewlineが指定されている場合には末尾に改行コードがあれば削除される。

seek $fileID $offset $origin

識別子$fieldIdファイルのアドレス$offsetにシークする。
$originはstart,current,endのいずれか。
省略するとstart。

tell $fileID

識別子$fileIdファイルの現在のアクセス位置を返す。

eof $fileID

識別子$fileIdファイルのアクセス位置がeofに達している場合は1を、それ以外の場合は0を返す。

file $option $fileName arg...

ファイル名$fileNameのファイルに$optionで与えた操作を行う。
$optionは下記のいずれか。

atime
最後に参照された時刻を返す
dirname
ファイル名からディレクトリ名を取り出す
executable
実行可能なら1を返す
exists
存在し、アクセス可能なら1を返す
extension
ファイルの拡張子を取り出す
isdirectory
ディレクトリファイルなら1を返す
isfile
通常のファイルなら1を返す
lstat
lstatのシステムコールを実行しargで与えた変数に結果を返す
mtime
最後に修正された時刻を返す
owned
現在のオーナーが自分なら1を返す
readable
読み込み可能なら1を返す
readlink
リンクファイル名を返す
rootname
最後のドットまで(ドットは含まない)の文字列を返す
size
ファイルサイズを返す
stat
システムコールstatを実行し、argで与えた変数に結果を返す
tail
ファイル名を返す
type
ファイルの種類を返す。種類はfile,directory,など
writable
ファイルが書き込み可能なら1を返す

flush $fileID

バッファに蓄積されているデータを識別子$fileIdのファイルに吐き出す。

glob $switch $pattern $pattern...

$patternに合致するすべてのファイル名のリストを返す。

pwd

現在の作業ディレクトリ名を返す。

内部情報の取り出し(Infoコマンド)

infoコマンドはTclインタープリタが保持している内部情報を取り出します。

info args $procname

$procname(プロシージャ名)のアーギュメントリストを返す(bodyを参照)。

info body $procname

$procname(プロシージャ名)の中身を返す。

tclsh.exe
% proc test {a b } {
% return [expr $a * $b]
% }
% info args test
% a b
% info body test
% return [expr $a * $b]

info cmdcount

プロシージャが現在までに実行したコマンド数を返す。
info cmdcount自身も数に含まれる。
※ブラケットで囲まれたコマンドの実行(コマンド置換)は数にふくまれません。

info commands $pattern

$pattern(プロシージャ名の検索文字-glob型式・省略可)に、合致するプロシージャのリストを返す。
内部コマンドも含まれる。
$patternを省略すると全てのコマンド・プロシージャのリストを返す。

info complete $command

$command(コマンドライン)に与えられたコマンドラインが正しく完結しているか調べる。
完結していれば1を返す。
ダブルクオートやブラケットなどが閉じていない場合は0を返す。

tclsh.exe
% info complete {set a "this is a pen}
% 0
% info complete {set a "this is a pen"}
% 1

info default $procname $arg varname

$procname(プロシージャ名)の$arg(そのプロシージャの中のひとつのアーギュメント名)のデフォルト値を調べる。
デフォルト値を持たない場合は0を返す。
デフォルト値をもつならばその値をvarnameにセットして1を返す。

tclsh.exe
% proc test {{a 3} b} {
% return [expr $a * $b]
% }
% info default test b var
% 0
% info default test a var
% 1
% puts $var
% 3

info exists varname

変数varnameが存在するか調べる。

info hostname

PCのホスト名を返す。

info level $number

$number (コマンド階層・省略可)を省略すると現在の階層番号を返す。
$number を与えると、その階層のプロシージャ名を返す。
$number は自分の階層より小さい値(上層)を指定する(1以上)。
例えば、testプロシージャからコールされるtest2プロシージャ内でinfo levelを実行すると2がリターンされる。
そして、続けてinfo level 2を実行するとtest2が返されinfo level 1を実行するとtestが返される。

info library

ライブラリが格納されているディレクトリを返す。
これはグローバル変数 tcl_libraryの値。
sourceコマンドにおける、tclソースファイルのデフォルト格納先である。

info locals $pattern

ローカル変数リストを返す。
$pattern(変数名の検索文字列・glob型式・省略可)を省略すると全てのローカル変数名リストを返す。
$patternを与えると合致するローカル変数リストのみを返す。
ローカル変数とはglobalおよびupvarで宣言されていない、プロシージャ内部の変数で、ローカル変数にはプロシージャのアーギュメントも含まれる。

info nameofexecutable

実行ファイル名を返す。

tclsh.exe
% info nameofexecutable
% A:\WinGeo\tclsh.exe

info patchlevel

グローバル変数tcl_patchLevelの値を返す。

info procs $pattern

$pattern(変数名の検索文字列・glob型式・省略可)を省略すると、現在の名前空間内の全てのプロシージャ名リストを返す。
$patternに名前空間名を検索文字として与えると、その名前空間内に定義されたプロシージャ名リストを返す。

info script

tclソースファイル名を返す。
sourceコマンドで評価されるソースファイル内に記述されたとき有効。

info tclversion

tclのバージョンを返す。

info vars $pattern

現在アクセスできるグローバル及びローカル変数リストを返す。
$pattern(変数名の検索文字列・glob型式・省略可)を省略すると全ての変数名リストを返す。
$patternを与えると合致する変数リストのみを返す。
変数にはプロシージャのアーギュメントも含まれる。