Tcl/Tkの日本語の扱い

 Tcl/TkはPerl、Python、Schemeといったスクリプト言語の中でも、 日本語の扱いは飛びぬけて優れています。 Tcl/Tk 8.1以降ではJavaと同じく、本体処理系が文字列を、 非英語圏の複数バイト文字に対応したUnicodeの一種、 UTF-8で扱うようになりました。 もちろん、世界中の言語の文字に対応したわけではありませんが、 日本語の文字列としての扱い、Tk部品への表示、 ファイル読み書きは 8.1 から、Tk部品へのキー入力は 8.3 の後半から、 ほぼ問題なく行えるようになっています。
 実際のところ他のプログラム言語では、 英語のアルファベット以外の言語圏のサポートについては中東欧やロシア圏のみ、 という状態で足踏みしているものが多いのですが、 Tcl/Tkは非英語圏に踏み出したバージョン8.1 でいきなり日中台韓の極東圏で使われる大部分の文字コードを取り込み、 大きな進歩として歓迎されました。 Tkについても、最初は不安定だったのですが、バージョンが上がるごとに様々な不具合が解消され、 現在ではとても安定した環境になっています。

●文字列として使う
 日本語の文字列も、普通にスクリプト中に含めることができます。 ただし、Windowsの場合はシフトJISコードで、UNIXの場合は環境変数LANGやロケ−ル (ロカール)で指定した文字コードでスクリプトを書く必要があります。

set a "日本語っす"
「string length」など、文字列を扱うstringコマンドも、 すべて日本語など多バイト文字を考慮しています。たとえば、
string length "日本語EUC"
とすると、9ではなく6(日本語の文字も1文字とカウントするため) が返ってきます。regexpコマンドの正規表現も、 特殊なものを除いておおむね日本語を含めることができるようです。
 文字列が全角文字を含むかどうかを判断する基本的なテクニックとして、 「string length」と「string bytelength」をそれぞれかけたときの戻り値を比べる、 というのがあります。Tclは全角文字を1文字3バイト(UTF-8だから)で持っているので、 string bytelengthコマンドの戻り値は全角文字の数×3+ASCII文字の数となります。

●Tkウィジェットへの表示
 ラベル、ボタンなどのテキスト、エントリやテキストボックスのテキスト、 キャンバスに描くテキストなどにも、 日本語を指定することができ、 日本語フォントがOSにインストールされていれば、前のページで紹介したように、 日本語を表示することができます。

  button .b -text 終了 -font kanji16 -command exit
  pack .b
このとき、-fontオプションで必ずしも日本語のフォントを指定する必要はありません (適当に合うのが探される)。 Windowsでは、
-font {{MS ゴシック} 20 normal}
のように、フォント名にも日本語をそのまま指定することができます。

●Tkウィジェットへの日本語入力
 Windowsでは、8.1の頃から日本語をエントリなどに入力することは可能でしたが、 デスクトップの隅に変換ウィンドウが出る形の入力形式で、 ちょっとまだるっこしいものでした。 現在の8.4では大幅に改善され、普通の日本語対応のアプリケーションと変わらない、 インライン入力が可能となっています。

 一方UNIXですが、 8.2、8.3でも非英語圏の文字を入力できるようにというサポートは模索されましたが、うまくいきませんでした。 8.3.1の頃から、 ようやくXIMP(X Input Method Protocol)を使った日本語入力が安定してきました。 ここでは代表的な日本語かな漢字入力システムの「うんぬ」や「かんな」 の変換サーバを起動しておき、 それらと通信する代表的な日本語かな漢字変換フロントエンド「kinput2」 を使ってTkのエントリに日本語を入力する例を試してみます。
前準備として、

  • 「うんぬ」のサーバープロセス(jserver)または 「かんな」のサーバープロセス(cannaserver)が起動しているのを確認します。
  • kinput2を起動し、KTermやTgif+などで日本語の入力が可能なのを確認します。
tk useinputmethods 1
entry .ent -font kanji16
button .cmda -text OK -command {
    tk_messageBox -message "入力内容: <[.ent get]>"; exit
}
pack .ent .cmda -side top -anc e
  • 日本語入力を可能にするには、 事前に「tk useinputmethods 1」を実行しておく必要がある
  • 入力対象のエントリの-fontには、日本語フォントを指定しておく必要がある
  • 日本語変換開始キーを押すときには、キーフォーカスがエントリなどの入力可能なTkウィジェットに合っている必要がある
の3点を注意すれば、うまくいくと思います。
 ちなみに、当然、入力した内容は正しいTcl文字列として格納されます。

●ファイルの読み書き
 日本語のテキストを読むときには、そのテキストファイルがどの文字コード (iso2022-jp(いわゆるJISコード)、シフトJIS、日本語EUC) で書かれているかをあらかじめ知っておく必要があり、 fconfigureコマンドの-encoding オプションで指定します。

set fin [open japanese.txt]
fconfigure $fin -encoding euc-jp
set line 1
while {! [eof $fin]} {
  set a($line) [gets $fin]; incr line
}
close $fin
-encodingを指定しなかったときは、OSのデフォルト (Windows日本語版ならcp932(*2)、 UNIXならLANGやロケ−ルによる) から適当に決められます。
(*2) 「shiftjis」というエンコーディングもありますが、 日本語Windows環境の文字コードは厳密にシフトJISコードというわけではなく、 いわばマイクロソフト独自の亜派で、そのエンコーディングの名前が「cp932」です。 UNIX環境でのシフトJIS(ja_JP.PCKなど)は当然、「shiftjis」となります。

 日本語の文字列をファイルに書き出すときにも、 書き出すときに使う文字コードを、 上と同様にfconfigureコマンドの-encodingオプションで指定します。

 下の例はエラー処理もろくにというか全くしてない簡単なスクリプトですが、 シフトJIS(正確にはcp932)で書かれているテキストファイルを全部一気に読み、 その内容を日本語EUCで別ファイルに書き出す、というコンバータです:

set fin [open infile.txt r]
set fout [open outfile.txt w]

fconfigure $fin -encoding cp932
fconfigure $fout -encoding euc-jp

puts $fout [read $fin]

close $fin
close $fout

 ちなみに、ファイルや文字列がどの日本語文字コードで書かれているかを、 ファイルの中を覗いて適当に(このへんが、なんとも怪しいですが) 推測するTclコマンドがこちらのDPU拡張に含まれています。

●UNIXでシフトJIS環境の場合
 産業情報システムの世界では、例えば半角カナの過去の遺産をひきずっていたりする関係で、 UNIXサーバでもOSやツールがシフトJIS環境をメインに想定していたり、 シフトJISの方が扱いやすかったりすることがあります。 このUNIXでシフトJISという環境下では、

  • Tclスクリプトをどのエンコーディングで書くか
  • 標準出力をどのエンコーディングで行うか
にちょっと注意が必要です。
 tclshやwishが読み込んで実行するスクリプトは、 自分自身が書かれているエンコーディングを、 自分のスクリプトの中で指定することはできません(※1)。 これには、tclshやwishの実行前に環境変数LANGを正しく設定しておく必要があります。 例えば、シフトJIS環境でも、 実行直前にLANGをjapanese(大半のUNIXプラットフォームで日本語EUCのこと) にしておけば、日本語EUCで書かれたTclスクリプトを実行できます。 ただし、ヒューレットパッカードのHP-UXだけは、 japaneseというのはシフトJISを指すので、注意が必要です。
 ファイルの読み書きは、先述の通り個々のファイルに対して、 そのファイルがどのエンコーディングで書かれているかをあらかじめ知っておき、 fconfigureコマンドを使えば指定できるので、あるファイルは日本語EUC、 あるファイルはシフトJISというのを、Tclスクリプトの中で選択でき、 とても便利です。これと同様に、標準出力のエンコーディングを切り替えることも可能です。 例えば、LANGがjapanese(日本語EUC)の環境下で、 Tclスクリプトの標準出力をシフトJISにしたい場合には、
fconfigure stdout -encoding shiftjis
とすればOKです。
(※1) 2005/06/18注: Tcl 8.5では、tclshやsourceコマンドに-encodingオプションが新設されました。これによって、 /bin/shとして実行しexecでtclshに化ける形態のTclスクリプトであれば、 自分自身がどのエンコーディングで書かれているかを、 Tcl処理系に明示的に伝えることができるようになりました)


Tcl/TkとUnicode

 XMLによるテキストファイル処理が本格化してきた昨今、 日本語のテキストを従来の文字コード三強(JIS、シフトJIS、日本語EUC) ではなく、Unicodeで保存する方法も台頭してきました。 若干扱えない文字種があるなど難もあるものの、 Unicode対応のフリーウェアのテキストエディタが現れたり、 Javaテクノロジーの影響を受けて、 RDBMSなど業務製品が徐々にUnicodeに対応したり、と、 その範囲は浸透しつつあります。
 Unicodeを表記するためのエンコーディングの中で、 UTF-8とUTF-16(いわゆるUnicode)の2種類が普及しています。 Tcl/Tkでも、エンコーディング「utf-8」「unicode」が用意されており、 これらを上記のshiftjis、euc-jp、iso2022-jpなどと同様に扱うことができます。
 例えば、上のまねですが、シフトJISで書かれたテキストファイルを読み、 UTF-8で保存するには、次のようにします。

set fin [open infile.txt r]
set fout [open outfile.txt w]

fconfigure $fin -encoding cp932
fconfigure $fout -encoding utf-8

puts $fout [read $fin]

close $fin
close $fout

 私がはまったのですが、Tcl処理系が内部的に文字コードをUTF-8で保持しているからといって、 「-encoding binary」でなまテキストとして出力しても、 これはUTF-8と等価ではなく、化け化けになってしまいます。 要注意、ですね!

やねうらの top
(first uploaded 2000/06/28 last updated 2005/06/18, MISUMI URANO)