The TECkit Language

The TECkit language

[32] The TECkit language (.map ファイル) は、 TECkit で使われている文字コードの変換の規則を記述するファイル形式です。

仕様書

[1] >>11 は言語仕様というよりは利用の手引の類で、その種のものにしては細かく説明しているものの、 ファイル形式の形式と意味の規定としてみると精密さに欠けます。

[33] >>11 の他に TECkit のプログラムの挙動やソースコード、 あるいは実際の .map ファイルの利用事例を見て研究する必要があります。

公式資料

[15] >>14 申し訳程度のテスト

概略

[48] 主に文字コード変換に使われます。 Unicode ではない従来の文字コードUnicode との相互変換の方法を記述することができます。

[49] 文字コードの変換の実装は多く存在しますが、 TECkit は主に東欧から中東南アジアにかけての地域などの文字を使う研究者に使われることが多いようです。 そうした研究者はいわゆるフォント依存符号化のような専用の文字コード体系を20世紀末から21世紀初期に使っていましたが、 欧米の商用製品が実装している文字コード体系とは違うものが多く、 当該地域の一般住民の使っていた文字コード体系とも必ずしも一致していないので、 専用の実装を必要としています。

[51] .map1対1の単純な写像だけでなく、 前後の文脈に応じた複雑な変換処理を記述できます。 記述能力は正則表現に近いですが、 無限の反復を認めないなど制限があります。

[66] Unicode 以前の文字コードUnicode とでは基底文字結合文字の順序が逆のことがあり ( 非spacing文字 )、 その場合逆転させる規則が必要になります。

[67] 印度系文字の文字コードUnicode とでは文字の扱い方が大きくことなる場合がほとんどです。 従来文字コード、特にフォント依存符号化8ビット符号フォントの限られた字数の制約と既存の文字のレンダリングの仕組みの流用という仕組み上、 文字の素朴な見た目をそのまま順番に表現していることが多いです。 一方 UnicodeUnicode 独自の理論に整合する一貫した方法を採用しているので、 かなり複雑な組み合わせで記述することになります。 文字のレンダリングの際には complex script の処理と言われる複雑な手順で Unicode文字列グリフ列に置換することになりますが、 おおよそこれに相当する変換処理が必要になります。

[68] 南アジアの現地住民による実装などを除けば、汎用のソフトウェア (Webブラウザー等) の文字コードの変換の処理では >>67 のような複雑なものはほとんど実装事例がなく、 TECkit.map の大きな特徴といえます。

[69] それはつまり、欧米の商用ソフトウェアがこの地域のデータの互換性の問題を切り捨ててきたということでもあります...

[50] .map では変換の一方を左辺 (LHS)、他方を右辺 (RHS) と呼んでいます。 順方向の変換 > は左辺から右辺に、 逆方向の変換 < は右辺から左辺にと行われます。 演算子 >, <, <> を使い分けて1つのファイルで両方向の関係を同時に記述します。

[52] .map では Unicode でない文字コードを byte、 Unicode のことを Unicode や uni と呼んでいます。

[53] .map は変換を多段で記述でき、 各段のことを pass と呼んでいます。 順方向では前 pass の右辺が次 pass の左辺になります。 pass の入出力は byte または unicode で4種類あり、 byte_unicode (左辺 byte, 右辺 unicode)、 unicode_bytebyteunicode と呼ばれています。

[54] >>53 の他に NFCNFD の適用を表す pass があります (必然的にそれらは unicode から unicode への変換になります)。 また、 LHSFlagsRHSFlagsExpectsNFC, ExpectsNFD という値があり、入力が NFC, NFD であることを期待する指定ができます。 .map の処理の前段階として適用することになります。

[55] LHSFlagsRHSFlags には GenratesNFC, GeneratesNFD という値もありますが、どちらかというと処理の指定ではなく処理結果を表明するもののようです (保証するわけではありません)。
[56] NFC / NFD は破壊的な操作なので ( Unicode正規化 )、 通常は利用を躊躇されるべきものですが、 文字コードの変換というのが本質的にそれ以上に破壊的で危険な操作ですし、 対象となる文字コードの性質をよく理解した者が .map を書く分には使っても構わないのでしょう。 適切に使えば写像を単純化できます (Unicode合成済文字が多いラテン文字で特に有用そうです)。

[57] pass が明示されていないと、全体が byte_unicode の1つの pass になります。

[58] pass の数や種類には制限がないようです。 ただし前段の出力と後段の入力が矛盾するものは認められません。 多段化することで複雑な変換を単純に書けることもある一方で、 全体の入力と出力の関係性が非常にわかりにくくなります。

[59] すべての pass を組み合わせた全体としては byte から unicode となるものが多いですが、 そうでないものもあります。


[60] 変換の両辺は byte や unicode の文字1つと一致することもあれば、 いくつかの文字の列と一致することもあります。 空に置換される (削除される) こともあります。

[62] 変換の両辺には一致部分の他に、直前の条件や直後の条件やその両方を書くこともできます。

[63] 一致や条件は反復数を指定することもできます。ただし15個までに制限されていて、 無限の連続は指定できません。

[64] 条件には文字の他に境界を表す # も指定できます。

[61] 変換の規則は何個でも書くことができます。 複数の規則に一致する場合は、一致部分 (前後の条件も含む。) の文字数が長いものが優先されます。 同数なら .map の先のものが優先されます。 (.map に記述した要素数ではなく一致した文字数です。)

[65] >>61 のために .map の解析は一見して感じられるものよりかなり複雑になります。 単純に変換処理をしたいだけなら上から順にすべて処理して選べばいいだけですが、 変換表の性質を理解したいときは前後の条件や文字クラスや反復が相互にどう作用するのか見極める必要が出てきます。

実利用例

[2] >>8 から

[4] >>3 注釈に ISO/IEC 8859-1 と思われる文字

[16] >>13 Copyright の値 (文字列リテラル) に UTF-8 文字©を含む事例

[18] >>8 に含まれる .map ファイルの限りにおいては考慮するべき非ASCII文字>>16 のような© (UTF-8) のみのことがほとんどです。それ以外は注釈非ASCII文字が含まれることも少なくありませんが、 UTF-8 のものだけでなく >>4 のような事例も紛れ込んでいるので注意が必要です。

[36] >>34 は例外で、変換式の文字列リテラルでも UTF-8 文字を使っています。

[39] UTF-8 BOM が先頭についているファイルがあります。

[20] >>19 改行0x0D のみの事例

[23] >>21 ", >>22 ' で始まる文字列リテラル改行まで閉じられていない事例

[24] TECkit のソースコードを見ると改行リテラルの終わりと明示的に作られていて、 エラーメッセージも特に出していません。

[35] >>34

EncodingName            "a canonical name that uniquely identifies this mapping table from all others"
DescriptiveName         "a string that describes the mapping"
Version                 "1"
Contact                 "mailto:user@addr"
RegistrationAuthority   "the organization responsible for the encoding"
RegistrationName        "the name and version of the mapping, as recognized by that authority"
Copyright               "© 2017 <CompanyName>. All rights reserved."

とあまりに雑なメタデータ。 そう、処理に使われないメタデータは真面目に書いてもらえない(ことがよくある)、 これは世界の普遍の法則。

[41] >>40

Contact                 "mailto:(@sil.org)"

なんだこの mailto: URL は。 mailto: の続きは RFC 822 メールアドレスなので括弧に含まれるのは注釈。・・・ではさすがにないと思われるが。

[76] なお公式ドキュメント >>11 では Contact の値は mailto: URL が typical form と書いているだけなので、 実は何でもいいということに。実際 >>74

Contact 'Bob Hallissy at SIL'

としていてもはやメールアドレスですらない。

[38] >>37 VisualOrder を指定した事例 (他にほとんどない)

[72] >>71 左辺が byte であるにも関わらず LHSFlags に ExpectsNFC を指定した事例

[7] >>6 ByteDefault0x3F 以外を指定した事例

[73] ドキュメントによると ByteDefault, UniDefaultbyte_unicode, unicode_byte の pass に属するべきものです。ところが >>70.map 上に明記された pass は1つで unicode。 その直前の pass に属さない部分に UniDefault があります。 byte との変換が発生し得ないのでこの UniDefault には意味がありません。

[17] >>13 入出力両方とも Unicode の事例

[78] >>77 pass が9段階もある事例

[47] >>46Unicode - Unicode 変換という形式になっているが、 左辺の Unicode は実際には Windows-1252フォントの一部文字を独自に差し替えたもの。 CRWindows-1252 が割り当てた文字があるので Latin1 以外の領域の Unicode文字も左辺に入ってくる。

[75] >>74Unicode から Unicode への変換ファイルの事例

[80] >>79Unicode から byte への変換ファイルの事例。 pass が Unicode_Byte になっているのは非常に珍しい。 注釈によると UTF-8 に誤変換されたデータを処理するときに前段としてこれで8ビット符号に戻すために使うとのこと。

[5] >>3 バイトクラスUnicodeクラスで定義されている対応と直接記述されている対応で重複がある (どちらの定義も同等)。 U+00D1, U+00D2, U+00D3, U+00D4 この他にも何らかの理由重複される変換式があって一方が常に無視されるものが含まれるファイルはかなりある。 (双方向の変換式でうち一方向が無視されるものもある。)

[26] >>25 >>40 PUA という謎の値が出現する事例。ドキュメントにある字句の中だと定義 (マクロ) か、 そうでなければ文字の名前扱いになるはずだが、 そのような定義は無いし、 文字の名前PUA であるものは存在しない。また、 PUA というクラスが定義されているわけでもないし、 クラスは構文も違う。 このような PUA が変換式に含まれるファイルは他にもいくつかある。

[42] >>40

0xD7    <>      U+256B BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE  --  SILID 9090* + SILID 0129 (space glyph ignored) + SILID 9090* + SILID 9090* + SILID 9090* + SILID 9075*

なんだこの行は。他の行と比べると本来 BOX の前に ; が入って注釈になるべきが何らかの理由で消えてしまったか。 しかしこのファイルで TECkit は読み込めるのか。 それともコミット後に誰も使っていないのか。

[12] >>9 変換先が U+FFFD を含む文字列の事例 (人間向けに注釈あり)

[43] この他 ByteDefaultUniDefault が変換式に直接出てくる事例はいくつもある。 変換先が存在しないものであることを明示的に示したかったのか、 あるいは変換式同士の優先順位の関係で明示しないといけないケースもときにはあるのか。

[44] <> なのに変換先が U+FFFD のものが複数ある (つまり逆変換が重複しているので1つ以外は無視される) というケースもたまにあって、そういうのは何も考えて無さそう。

[28] >>27 'id ' から始まるおもしろい変換式。 \id から始まる行は通常の変換ではなくそのまま ASCII から Unicode に写像する意図らしい。 .map の表現力で無理矢理記述した結果と思われる。 言語仕様ドキュメントではクラスはその位置で対応付けるとしか説明がなく、 クラス以外の字句の扱いが不明瞭だし、 .map の字句の位置なのか一致した文字列の数(?)なのかよくわからない。ソースコードを読んだ感じだと、 .map 上の字句の数で対応付けているように見える。 が、そうだとするとこの変換は正しく処理されないような気もするが... なお同じ変換式があるファイルが他にもいくつかある。

[125] 左辺で @ を使った事例がいくつか

[30] >>29 (X=a | Y=b) <> @a @b 型の変換式がある。 | による選択があることに注意。 <> なので両方向の変換に使われる。 左辺から右辺への変換は良いが、右辺から左辺への変換でこれが何を表すのか、 言語仕様ドキュメントを読んでも判然としない。 他のいくつかのファイルにもこの形式の変換式がある。

[31] >>30 はおそらくいずれも特定の種類の文字列における文字の出現順序を一定に揃えるもので、 <> になってはいるものの、実際には左辺から右辺への変換でしか使われないと思われる。

[45] ファイル仕様上はすべてのファイルが正方向と逆方向の両方の変換に対応することになっていそうだが、 実際のファイルでどこまでしっかり作り込まれているのかは怪しい。正方向が動作するのは当然として、 逆方向が不安なものもちらほら。また、 > ばかりで逆方向の変換が皆無のファイルもあって、 当然逆方向に変換しても意味がない (未対応という意味で意図的にそうしているのかも)。


[131] >>129 build/make したら .map が生成される

[132] >>129 pass(NFD) を使った事例

[133] >>129 .* を一致部分に使った事例

[134] >>129 deva-san.map が pass 10段階

[135] >>129 独自?の PUA に変換しているものも多い。 U+FFFD に変換しているものも多い。

[86] >>84 Define U している事例。字句解析で気をつけないと U+1234U を置換してしまう。

[87] >>84, >>96 条件付きの削除 (右辺空) の事例

[95] >>90 条件に . (任意の文字) の事例

[136] >>137 arabtex-farsi-fullvoc.map^# の事例


[83] >>82 UTF-8 文字の文字列リテラルを利用。

[119] >>117 変換式の末尾の文字列リテラルを閉じる " がない事例

[97] >>93

U+0905U+0902<>U+1E43;अं ṃ
U+0905U+0903<>U+1E25;अः ḥ
U+0905U+0901<>U+006FU+0302;अँ ô

のように U+ 字句の間に空白がない事例

[98] >>89 U+1E6D 'U+1E6C h' 'U+1E6D h' U+1E0C のような値がある。 ただの文字列リテラル。何を意図していたものか。

[99] >>89 UniClass の定義中に文字列リテラルUTF-8 文字も。

[126] >>123 pass が11段もある事例。流通しているファイルの中ではこれが最大か?

[127] >>123 ([X])=a <> ([Y])=a 型のグループ化で一見隠された文字クラス同士の対応関係を使う事例


[100] >>91Unihan から機械的に生成したらしいファイル。 >>88 にもある。

[101] >>91 はとても雑で、 Unihan異体字を列挙 (or) したものまでそのままにしているので、 異体字が並んだ文字列が変換結果になってしまっているw データの意味も理解しないで雑に処理して検証もしていないということ。

[102] なお簡体字繁体字の変換は中華圏で需要が多く専門のソフトウェアやデータが盛んに開発されていて、 そちらの方がより正確で豊富。 異体字データベース

[103] >>91 はおそらく .map として流通しているものの中でも変換式の量は最大級なので、 そういう検証には有用。ただ .map としての複雑度は簡単な部類。 >>102 のようなデータは (.map ではないが) もっと複雑なことをしている。 TECkit簡体字繁体字の変換にも適用可能かというのは理論的に面白いテーマではある (>>91 はその回答にはまったくなっていないが)。

関連

Graphite Description Language

メモ

[120] Bibledit, , https://web.archive.org/web/20210618185016/https://www.nongnu.org/bibledit/teckit_mapping_rules_reference.html