From: Martin Duerst Date: 2007-12-13T17:30:28+09:00 Subject: [ruby-dev:32576] Re: transcoder loading 中田さん、こんにちは。 At 16:43 07/12/13, Nobuyoshi Nakada wrote: >なかだです。 > >At Thu, 13 Dec 2007 13:27:57 +0900, >Martin Duerst wrote in [ruby-dev:32572]: >> >transcoderを拡張ライブラリに出してみました。ext/とは別にしたほう >> >がいいかもしれませんが。 >> >> その通りだと思います。これからデータのファイルが増えるので、 >> メインのところにはちょっと不便ですが、ext にするといちいち >> require が必要になると思いますが、これはとても不便だと思います。 >> require が必要になったら結局 String#encode が定義されているが、 >> require しないと使えない、という不思議な現象になってしまうでしょう。 > >requireは自動的に行うように考えています。 パッチを最後まで読んだところでそれができている様な来もしました。 >> ファイルの場所を考えると、enc の中、もしくは enc/trans では >> いいのではないかと思います。 > >最初はenc/transを考えていたのですが、結局やることはextと同じなの >で、とりあえず手を抜きました。 > >> >include/ruby/transcode.hとext/enc/trans/iso_8859/iso_8859.cは、 >> >それぞれtranscode_data.hとtranscode_data_iso_8859.cをsvn mv した >> >ものです。 >> >> 細かいところだけいいますと、/iso_8859/ の部分は要らないと思います。 >> ファイル一つだけのためのディレクトリは余り意味がないと思います。 > >extmk.rbで扱うための手抜きの他に、複数ファイルに分ける場合がある >かもしれないということです。 > >> しかも、iso-8859 見たいに標準にそってファイルをまとめることに >> は長期的にはならないと思います。データの効率を考えると文字種 >> (例えば Latin、Greek、など) にそってまとめた方がいいと思います。 > >これはちょっとよくわからなかったんですが、たとえばLatin文字セッ >トの各encodingでのcodepoint表を作る、といったことでしょうか。 > >言語ごとに作業を分けられるというメリットがあるかと思いますが、 >String#encodeでの指定などはどういう風になるんでしょうか。 作業の話のではなく、データの話です。似たような文字を扱うコード変換で データをある程度共用できますので、例えば iso-8859-1 (文字種: Latin) と iso-8859-7 (ASCII 以外の文字種: Greek) を一緒にするのではなく、 iso-8859-1 と windows-1252 を一緒にした方がいいです。現在の データ構造だとこれはなぜだろうかということは見えないが、次の 段で見えてくると思います。いずれ今のところどの文字コードはどのぐらい のデータが必要になるのか、どの文字コードを共通のファイルにするのか、 大体一発ロードするものでは何キロバイトぐらいが適切なのか (極端に rubygems でメガ単位で増えたとしたら文字コード変換では 二三百キロでわさわさ動的にロードする必要がないという意見もある かも知れませんので)、今ディレクトリに小分けするのは早すぎだと 思います。 >> 後は、(予定していた) transcode.h と (既に存在する) transcode_data.h >> は別物として考えています。transcode.h はルビから使える機能を定義し、 >> transcode_data.h はデータ形式関係のものを定義し、ルビからは >> アクセスしなくていいもの、という考え方です。 > >了解です。 > >> >-/* in the future, add some mechanism for dynamically adding stuff here */ >> >-#define MAX_TRANSCODERS 29 /* todo: fix: this number has to be adjusted >> >by hand */ >> >-static transcoder transcoder_table[MAX_TRANSCODERS]; >> >+static st_table *transcoder_table; >> >> ハッシュにするのはありかと思います。 > > > >> >+#define TRANSCODER_SEP '@' >> >> これは内部だけの決まりだと思いましたが、ファイル名にまで使われているので、 >> 十分検討した方がいいと思います。 > >requireするときには'/'に書き換えるということも可能でしょう。実際 >最初はそのようにしたんですが、ディレクトリが多すぎるように感じた >のでこのようにしてみました。 '/' は確かにそういう問題になりますので止めた方がいいと思います。 >> >+ for (s = key; *s; ++s) { >> >+ if (ISUPPER(*s)) *s = tolower(*s); >> >> 今まで見たところで、ルビ内の Encoding は全部大文字になっていますので、 >> なぜでここで小文字にしますか。 > >ライブラリ名は小文字という慣習が(おおむね)ありますので。 > そうですね。Encoding そのものが大文字になっているのは 定数として使えるためでしょうか。この辺りも方針をはっきり した方がいいと思います。 >> >+ rb_transcoding *my_transcoding) >> > { >> > char *in_p = *in_pos, *out_p = *out_pos; >> >- const BYTE_LOOKUP *conv_tree_start = my_transcoder->conv_tree_start; >> >+ const BYTE_LOOKUP *conv_tree_start = my_transcoder->transcode_arg; >> >> 変数、メンバーの名前を変える必要がないと思います。 > >抽象化のためです。rb_register_transcoder()に関数ポインタを渡すよ >うにすることで、str_encode()とtranscode_loop()は直接の関係を持た >なくなります。つまり、transcoderによってはtreeとはまったく異なる >ものを使うことになるかもしれません。 考えていることはよく分かります。しかしこれから変換の色々な 機能 (例えば変換不可能なときの対応等) を追加するとすると、 それぞれの具体的な変換関数に似たようなものをどんどん追加する必要 になってしまって、かなりだぶることになりかねないです。 抽象化は勿論考えていますが、ちょっと違うやり方を予定しています。 >> > transcode_loop(char **in_pos, char **out_pos, >> > char *in_stop, char *out_stop, >> >- transcoder *my_transcoder, >> >- transcoding *my_transcoding) >> >+ const rb_transcoder *my_transcoder, >> >+ int from_utf8, >> >> 変数を増やさない方がいいと思います。 > >> >+void >> >+rb_transcode_loop_from_utf8(char **in_pos, char **out_pos, >> >+ char *in_stop, char *out_stop, >> >+ const rb_transcoder *my_transcoder, >> >+ rb_transcoding *my_transcoding) >> >+{ >> >+ transcode_loop(in_pos, out_pos, in_stop, out_stop, >> >+ my_transcoder, 1, my_transcoding); >> >+} >> >+ >> >+void >> >+rb_transcode_loop_simple(char **in_pos, char **out_pos, >> >+ char *in_stop, char *out_stop, >> >+ const rb_transcoder *my_transcoder, >> >+ rb_transcoding *my_transcoding) >> >+{ >> >+ transcode_loop(in_pos, out_pos, in_stop, out_stop, >> >+ my_transcoder, 0, my_transcoding); >> >+} >> >+ >> >> 関数を増やす必要が現在内と思います。 > >transcode_loop()をコピーするよりは、フラグ引数のままのほうがよい >だろうと思いました。 そうですね。でもそもそも関数を複数作る必要がありません。 >> > /* for simple testing: */ >> >- transcode_loop(&fromp, &bp, (sp+slen), (bp+blen), my_transcoder, >> >&my_transcoding); >> >+ my_transcoder->transcode_loop(&fromp, &bp, (sp+slen), (bp+blen), >> >+ my_transcoder->transcode_arg, >&my_transcoding); >> >> やりたいことが分かりますが、あくまでもデータ中心にやった方がいいと思います。 > >テーブル駆動ということですか? iso-8859系とutf-8間ではそれがいい >と思いますが、必ずしもそういう変換ばかりではありませんから。 いいたいことはよく分かります。例えば Shift_JIS と EUC-JP の変換とか ですよね。心配しないでください。その辺りも考えています。 >> >Index: ext/enc/trans/iso_8859/lib/iso-8859-1@utf-8.rb >> >=================================================================== >> >--- ext/enc/trans/iso_8859/lib/iso-8859-1@utf-8.rb (revision 0) >> >+++ ext/enc/trans/iso_8859/lib/iso-8859-1@utf-8.rb (revision 0) >> >@@ -0,0 +1 @@ >> >+require "enc/trans/iso_8859" >> >Index: ext/enc/trans/iso_8859/lib/utf-8@iso-8859-1.rb >> >> いちいち一行のファイルを作るのはちょっとやりすぎだと思います。 >> もうちょっといい方法はないのでしょうか。 > >同感です。 何かいい方法はあるでしょうか。 >> このやり方でルビの内部でどの変換があるのか分からないという問題になる >> のもよく分かります。これは例えば force_encoding の ([ruby-dev:32563] >> など) と関係するだけではなく、utf-8 とか経由の二段階とかで変換するときにも >> 問題になりそうです。 > >変換パスを登録するDBのようなものが必要になりますかねぇ。 本当の DB の意味でしょうか。そうではなく何かのデータ構造に 前もって登録するように考えています。今のコードでいうと (rb_)register_transcoder を Ruby 全体の init 時にやって、 そこにロードされているかどうかやデータのファイル名など を追加する。 >> >+typedef struct { >> >+ const BYTE_LOOKUP *conv_tree_start; >> >+ int max_output; >> >+} iso_8859_transcoder; >> >> これは少なくともいまの段階で必要ないかと思います。 > >1.9.1までには少なくとも日本語の変換も可能にしたいです。 もちろんそうです。心配しないでください。 宜しくお願いします。 Martin. #-#-# Martin J. Du"rst, Assoc. Professor, Aoyama Gakuin University #-#-# http://www.sw.it.aoyama.ac.jp mailto:duerst@it.aoyama.ac.jp