RunRev1.1の日本語の現状を書いたまま途絶えていたので、2.0以降について少し補足しておくことにします。

 −−−−

RunRev2.1.2なワタシ

 ここで取り上げるのは主にRunRev2.1.2の日本語環境についてです。現時点でのRunRev最新バージョンは2.5なのになんでそんな中途半端なバージョンを取り上げるかと言うと、これが私の持っている最新のRunRevだからです(^^;)

 2004年にRuntimeRevolutionはライセンス形態を大幅に変え、従来の「ワン・ライセンスで全てのプラットホーム」から「各プラットホームごとのライセンス」に大幅転換しました。RunRevの魅力はいくつもありますが、「自分の作ったスタックをWindowsの人にも見て貰えるかも知れない」というのはかなり大きな部分を占めていましたので、これは少々ショックでした。

 後述するように2.5以降では日本語の扱いが改善され、面倒ながらも実用的な域にまで達していると思います。翻って2.1.2では、日本語がラップしないという、致命的とも言える欠陥を持っています。それでもライセンスを更新しなかった私が使えるのはこの2.1.2まで。なんとか誤魔化し組み伏せて、出来る範囲で日本語を扱ってみましょう。


RunRev2.1.2の日本語/フォントの指定

 2.0以降のRunRevではテキストフォント指定時にそのフォントの属性を指定できるようになりました。例えば

set the textFont of fld 1 to "Osaka"
↓
set the textFont of fld 1 to "Osaka,Japanese"
といった具合です。 item 1 は当然のようにフォント名ですが、item 2 は「文字をどのような規則で扱うかを決めるための情報」と思って下さい。 item 2 にJapaneseを指定することで、文字列処理に日本語独特の規則を適用することが出来ます。(ただし2.1.2では後述するラップの問題が解決されていませんし、2.5でも日本語の扱いはまだ完璧ではありません)

 日本語を扱うフィールドには、必ず ",Japanese" 付きでフォントを指定するようにして下さい。また set the textFont of this stack to "Osaka,Japanese" のように「スタックの」テキストフォントにも ",Japanese" を指定しておくと、IMなどの処理が正しく行われるようになるようです。

 ヘルプを読めば分かりますが、このJapaneseの部分にはKoreanやANSIなども指定できます。Unicodeの指定はどのような時に使うのか分かりませんでした。"Osaka,Unicode" を指定すると、化け文字になってしまいます。OS9では機能しないのかも知れません。

 Japaneseを指定したフィールドでは、日本語を普通にタイプすることが出来ます。ただし2.1.2では Don't wrap のチェックを外しても(つまり折り返しを指定しても)日本語は折り返してくれません。この部分は2.5で改良されているようです。
 苦し紛れの対処法として、フィールドの幅で強制改行するスクリプトを作ってみました。マックとWin95で動作確認してあります。 http://homepage.mac.com/udi/temp/jWrap10.rev.hqx( 27KB non-compressed )


RunRev2.1.2の日本語/文字列の出し入れの基本

 タイプした文字を取り出そうと put fld 1 into myText を実行しても、変数には思うような文字列が入ってくれません。また put myJapanese into fld 1 としてフィールドに日本語を入れようとしても、やはりおかしな文字に化けてしまいます。どうやらRunRevは独自の内部コードでフィールド内の文字を管理しているようです。ではどうやったらフィールドの文字を取り出せるでしょう。

 2.0からフィールドに、the unicodeText というプロパティが追加になりました。フィールド内の文字を Unicode に変換したものです。フィールドの文字プロパティには他に the htmlText や the rtfText などもありますが、プレーンテキストを扱うには the unicodeText が一番使い勝手が良さそうです。

 the unicodeText を活用するためにはS-JISとUnicodeの変換が必要になりますが、この関数も用意されています。例えば変数 jisStr にS-JISで書かれた日本語が入っているとします。これをフィールドに入れるには
put jisStr into fld 1 または set the text of fld 1 to jisStr
↓
set the unicodeText of fld 1 to uniEncode( jisStr )
とします。逆にフィールドの文字列をS-JISとして取り出したいなら、
put fld 1 into jisStr
↓
put uniDecode( the unicodeText of fld 1, "Japanese" ) into jisStr
とします。うーん。めんどくさい(笑)

 ファイルなどから読み込んだテキストは、それがS-JISであることが予め分かっていれば、uniEncode() を通してから the unicodeText プロパティにセットすれば良いです。またそれがUnicodeの文字列であることが分かっていれば、そのまま the unicodeText プロパティにセットします。RTFなら the rtfText 、html なら the htmlText プロパティにセットします。そしてどの方法でフィールドに書き込んだ文字列でも、the unicodeText で取り出してUnicode文字列を得ることが出来ますし、さらに uniDecode() を使ってS-JISに変換することも出来ます。このへんがRunRev独特の仕様で、ちょっと面白いですね。

 問題は、読み込んだファイルがS-JISかUnicodeか分からない場合です。正直言ってこれはお手上げです。ユーザー(スタックを使う人)に決めて貰うしかありません。以下は、そのような文字列を扱うフィールドの実装案です。

1.ファイルを読み込んだら、そのデータをフィールドのカスタムプロパティに保存する。
2.フィールドの横にポップアップメニューかラジオボタンを置いて、ユーザーがS-JISとUnicodeを切り替えられるようにしておく。
3.ユーザーがUnicodeを選択したら、カスタムプロパティの値を取り出して、フィールドの the unicodeText プロパティにセットする。
4.ユーザーがS-JISを選択したら、カスタムプロパティの値を取り出して、uniEncode() を通した上で、フィールドの the unicodeText プロパティにセットする。

 どちらが「まともに見えるか」をユーザーに判断して貰って、適宜切り替えて貰う訳です。文字コードの傾向を見てUnicodeかS-JISかを半自動で判断させるルーチンを作ることは可能な様ですが、極端な例ではたった1文字からでは、その文字列がどちらのコードなのかを判断するのは不可能です。プログラマとして不本意であっても、やはりユーザーにお願いするのが確実でしょう。

 Shift-JIS、Unicode UTF-8/UTF-16、EUCの4種に対応したテストスタックを作ってみました。EUCは自前の変換ルーチンで一旦SJISにしてから表示させてます。
http://homepage.mac.com/udi/temp/TextDisplayTest.rev


RunRev2.1.2の日本語/チャンク

 フィールドの一部分を取り出すことは比較的頻繁に行われますが、この時もUnicodeを介した面倒な方法で行わなければなりません。例えばフィールドの2行目を取り出すにはまずUnicode文字列を取り出し、それをS-JISに変換してから2行目を取り出します。
put line 2 of uniDecode( ( the unicodeText of fld 1 ), "Japanese" ) into jisStr
スクリプトをぱっと見ても、何をしているのか良く分かりません。元々xTalkは視認性がいい方だとは思わないですが、これは輪を掛けて悪くなりました。てか、最悪(^^;)


RunRev2.1.2の日本語/コピー

 文字列をクリップボードへコピーする場合は the clipboardData プロパティを使います。2.5では set the clipboardData["text"] to the selectedText が使えるようですが、2.1ではうまく行かないことがあります。で、苦労して作ったコピールーチンがこれです。
on copySelectedText
  -- どこが選択されているのか
  put ( the selectedChunk ) into chunkExp
  put word 2 of chunkExp into sPos
  put word 4 of chunkExp into ePos
  put last word of chunkExp into tgFld
  -- 当該フィールドのテキストをJISに変換
  put uniDecode( the unicodeText of fld tgFld, "japanes" ) into jisStr
  -- 選択されているチャンクを取り出してクリップボードへ
  set the clipboardData["text"] to ( char sPos to ePos  of jisStr )
end copySelectedText
 これでJISの文字列がクリップボードにコピーされます。もしUnicode文字列をクリップボードに入れたいなら、
  (略)
  -- 当該フィールドのテキストをJISに変換
  put uniDecode( the unicodeText of fld tgFld, "japanes" ) into jisStr
  -- 選択されているチャンクを取り出してUnicodeに変換
  put uniEncode( ( char sPos to ePos  of jisStr ), "japanese ) into uniStr
  -- Unicodeに変換した文字列をクリップボードへ
  set the clipboardData["unicode"] to uniStr
end copySelectedText
 となるわけです。set the clipboardDataの後に続いている ["text"] と ["unicode"] に注意して下さい。これはクリップボードにテキストタグ付きで格納するよ、Unicodeタグ付きで格納するよ、という意味です。このデータをペーストする時に、ペーストされる側のアプリケーション(もちろんRunRevのこともあります)がクリップボードに「何のデータが入っているのか」を知る手がかりになります。(文字列以外、例えばピクトデータを入れる場合は、ここに ["PICT"] と指定します)

 ふたつのスクリプトを見れば分かる通り、「Unicodeで取り出し」て、「JISに変換してチャンクの処理」をしてから、JISなりUnicodeなりをクリップボードに入れます。フィールドの入出力はUnicode、チャンク処理を含む文字列操作はJIS。少なくとも2.1ではこれが基本です。


RunRev2.1.2の日本語/カット

 この基本をふまえつつカットルーチンです。要するに選択されているテキストをコピーしてから消せばいいわけです。
on cutSelectedText
  -- とりあえずコピー
  copySelectedText
  -- どこが選択されているのか
  put ( the selectedChunk ) into chunkExp
  put ( word 2 of chunkExp ) into sPos
  put ( word 4 of chunkExp ) into ePos
  put ( last word of chunkExp ) into tgFld
  -- 当該フィールドのテキストをJISに変換
  put uniDecode( ( the unicodeText of fld tgFld ), "japanese" ) into jisStr
  -- 選択されていた場所を削除
  delete char sPos to ePos of jisStr
  -- Unicodeに変換してフィールドへ
  set the unicodeText of fld tgFld to uniEncode( jisStr, "japanese" )
  -- 削除した文字列の直前にキャレットを出す
  select before char ( sPos ) of fld tgFld
end cutSelectedText
 例によってフィールドの内容をUnicodeで取り出してJISに変換したあと、予め調べて置いた「選択されていた場所」を削除します。そしてこれをUnicodeに変換してから、フィールドにセットします。ああややこしい。

 削除したらそこにキャレット( I 型のチカチカするカーソル:挿入ポイント)を出す必要があるので、「選択されていた先頭」の直前をselectします。selectはフィールドでは通常、文字列を選択するコマンドとして使いますが、beforeやafterを使うことで、「位置」を選択することが出来ます。


RunRev2.1.2の日本語/ペースト

 更にペーストルーチンです。
on pasteOnSelectedText
  -- どこが選択されているのか
  put ( the selectedChunk ) into chunkExp
  put ( word 2 of chunkExp ) into sPos
  put ( word 4 of chunkExp ) into ePos
  put ( last word of chunkExp ) into tgFld
  -- クリップボードからjis文字列を取り出す
  if "unicode" is among the items of keys( the clipboardData ) then
    put uniDecode((the clipboardData["unicode"]),"japanese") into jisClip
  end if
  if "text" is among the items of keys( the clipboardData ) then
     put ( the clipboardData["text"] ) into jisClip
  end if
  put ( the length of jisClip ) into pasteLen
  if ( pasteLen = 0 )
    exit pasteOnSelectedText
  end if
  -- フィールドの内容をunicodeで取り出してjisに変換
  put uniDecode(( the unicodeText of fld tgFld ), "japanese") into jisStr
  -- 選択されていた部分にクリップボードの文字列を挿入
  put jisClip into char sPos to ePos of jisStr
  -- それをフィールドの文字列とする
  set the unicodeText of fld tgFld to uniEncode( jisStr, "japanese" )
  -- ペーストした文字の後ろにキャレットを出す
  select after char ( sPos -1 + pasteLen ) of fld tgFld
end pasteOnSelectedText
 まずクリップボードから文字列を取り出す部分ですが、if "unicode" is among the items of keys( the clipboardData ) で「クリップボードに "unicode" タグの付いたデータが入っているか」を調べています。もし入っていたらそれをJISに変換します。 "text" タグの付いたデータだったらそのまま取り出します。どちらも無かった場合はペースト処理を中断して抜けています。(htmlやrtfにまで対応させることも可能でしょうが、htmlやrtfからUnicodeやJISへの変換ルーチンが無いため、ダミーのフィールドなどを介する必要があります)

 例によってフィールドの内容をUnicodeで取り出してJISに変換したあと、予め調べて置いた「選択されていた場所」にクリップボードから取り出したJIS文字列をput。そしてこれをUnicodeに変換してから、フィールドにセットします。

 ペーストした文字列の後ろにキャレットを出すために、「選択されていた先頭」に「ペーストした文字列のバイト数」を足した位置をselectしています。


RunRev2.1.2の日本語/編集時の問題

 このように一旦JISにしてから再度フィールドにセットする方法では、フォントやスタイル情報は保持されず、文字列はプレーンテキストとして扱われます。つまり編集可能フィールドでは、単一のフォント/スタイルしか使えないことになります。1文字づつ文字情報を調べ、文字列をセットするときにそれを再現すれば、或いは可能かも知れませんが、長い文字列では実用に問題が出る程遅くなるでしょう。

 また2.1.2では日本語のワードラップ(折り返し)の問題が解決されていないので、強制的に改行を挟む方法(前述のjWrapスクリプト)では事実上編集は不可能と思います。私はここで紹介したカットルーチンやペーストルーチンは、折り返し不要のフィールド(例えば検索ワードの入力欄や、何かのリスト)でしか使っていません。2.5では日本語のワードラップがちゃんと行われるようになったので、もう少し実用的になっているようです。


RunRev2.1.2のテキストファイルの扱い

 RunRevはマルチプラットホームの差異を吸収するため、異なるプラットホームで作られたスタックを開くときに、スタック内のテキストを自動変換します。(JapaneseOnRR.htmlを参照のこと) 同様にして、テキストファイルの読み書き時にも、改行コードの自動変換が行われます。

 つまり、マックで書かれたCR改行のテキストファイルやWindowsで書かれたCRLF改行のテキストファイルはUnix風のLF改行テキストとして読み込まれ、逆にファイルに書き出す時は、現在のプラットホームに合わせてCRやCRLFに変換されてから書き込まれます。従来のxTalkの文法であるopen/read/closeまたはopen/write/closeを使った場合に、(readもしくはwriteコマンド実行時に)この変換が行われます。Shift-JISやASCIIならこれで問題が無いのですが、Unicodeデータの場合は不都合が起きます。

 そこで、Unicodeを扱う時は、ファイルを「テキスト」ではなく「バイナリ」で読み書きします。読むときは open にオプションを付けて open file myFile for binary read、書くときは open file myFile for binary write としてやれば、改行コードの自動変換が行われなくなります。

 或いは、url キーワードを使うことも出来ます。仮にファイルのパスを filePath とすると、put URL ( "file:" & filePath ) into abc でファイルの内容がそのまま abc に入ります。同様に書き出す時は、put abc into URL ( "file:" & filePath ) とします。 url キーワードを使った put では、データはバイナリと解釈され、改行コードの自動変換は行われません。


RunRev2.1.2のUnicodeファイルの扱い

 Unicode(UTF-16)のファイルには奇妙なオプションがあります。全ての文字を2バイトで扱うのがUTF-16ですが、その2バイトの上位下位バイトの並べ方に2種類あるのです。上位バイトを先に、下位バイトを後に書くのをビッグ・エンディアン、下位バイトを先に、上位バイトを後に書くのがリトル・エンディアンです。普通に考えるならビッグ・エンディアンが順当だと思うのですが、x86系のCPUではリトル・エンディアンのデータの方が扱いやすいため、このように2種類のフォーマットが作られたのだと思います。

 そのファイルがどちらの方法で書かれたものなのかを指定するために、UTF-16の先頭には BOM(Byte Order Mark)と呼ばれるものが付けられることがあります。先頭2バイトがFEFFならビッグ・エンディアン、FFFEならリトル・エンディアンです。BOMが無い場合はビッグ・エンディアンと解釈する場合が多いようですが、このへんの規格がどうなっているのか、良く判りません。

 RunRevでは the unicodeText of fld xxx や uniEncode() を使って Unicode(UTF-16) の文字列を作ることが出来ますが、この文字列には BOM は付きません。なので、Unicode のファイルを作る場合は、その先頭に FEFF を書き込む必要があります。また恐らくバグの一種と思われますが、RunRev の作った Unicode 文字列の先頭には、0(ゼロ=numToChar(0))が余分に付くことがあります。ファイルに書き出す前に、これは取り除いておかなければなりません。

 逆に読み込む場合ですが、これは少々ややこしいです。ファイルが Unicode であることがはっきりしているならBOM を調べ、BOMを取り除きます。



2005.03.03
2005.03.11
UDI

inserted by FC2 system