Hatena::ブログ(Diary)

はてなるせだいあり このページをアンテナに追加 RSSフィード

2014年11月07日(金)

文字列」について 19:13 「文字列」についてを含むブックマーク 「文字列」についてのブックマークコメント

「文字列を文字の列とみなす単純化」について議論がありますが、前提が抜け落ちてるように思うので書くことにします。

そもそもこの話はどのような文脈の上にあるかというと、テキスト処理 (wikipedia:en:Text_processing) の文脈になります。ここでいう「テキスト処理」とは plain text (wikipedia:プレーンテキスト) の検索・加工のことで、ここでは特に UNIX Text Processing の系譜が念頭に置かれています。つまり、複雑な装飾を含むリッチテキストではなく、処理の対象を ASCII 文字列といくつかの制御文字へと抽象化することで、正規表現のような強力な道具を用いた処理を可能とした世界です。UNIX でのお話ですから、ここでの具体的な処理の単位は char であり、全体としては char[] になります。この char の中身は上で述べたとおり、ASCII 文字列ですので、値は 0〜127 です。 (実際初期の UNIX tools は 8-bit clean ではなかった)

さて、アメリカ以外の国では (制御文字込みで) 128文字では当然足りないので、拡張が必要です。拡張の方針には

  1. ワイド文字: char を大きくする
  2. マルチバイト文字: 複数の char を組み合わせて、「1文字」にする

の2種類があります。

ワイド文字

ヨーロッパの言語ではアクセント付き文字を用いますが、これらは ASCII に収録されていません。ここで取られた策が 7 bit から 8 bit への拡大です。とはいえ、UNIX において char はたいていの場合もとから 8 bit でしたから、何か新しいものを導入する必要はありませんでした。

その後の wchar_t の導入や TRON コード、Unicode などでは、16 bit や 32 bit などのより大きな文字型が提案されています。

ワイド文字のメリットはプログラミングモデルはそのままで、型と関数だけを取り替えればより多くの文字を扱えることです。これにより、文字コードのことをよく知らない人でも国際化に対応したプログラムを開発出来ます。

デメリットは文字列型が変更されることでプログラムインターフェイスが変わってしまうことと、ネットワークなどのバイトストリームではそのままでは使えないことになります。

マルチバイト文字

複数の char を組み合わせて一つの文字を表すようにするのが「マルチバイト文字」です。

この方法の場合、プログラミングモデルは複雑になりますが、既存のプログラムを改修する際に、そのインターフェイスを維持したまま文字数を数えるなど必要最小限の変更で日本語対応させられることがメリットでした。

世界の選択

当初、世の人々はワイド文字こそが長期的には正しい選択だと考えていました。1 wchar_t = 1文字 は明らかにわかりやすい抽象化だからです。また、単一の文字コードUnicodeを採用することで国際化は格段に容易となることが期待されました。しかし、この考えは何重にも間違っていたことがその後明らかになります。

まずはUnicodeが16bitに収まらなかったことです。これにより、シンプルな16bit固定長だったUCS-2サロゲートペアを用いたUTF-16へと改修せざるを得なくなり、複数のワイド文字 (code unit) で1文字を表すという両者のデメリットを兼ね備えた方式へと堕ちました。

また、Unicodeが本格的に IVS をはじめとした文字の結合を扱うようになったことにより、複数のUnicode文字 (Unicode scalar value) を組み合わせて1文字を表す「結合文字列」を扱う必要が増し、結局プログラミングモデルの変更も必要となってしまいました。(なお、絵文字周りの話は文字コードのかなり上の方のレイヤーの話なので、今回の話とは全く関係ないと思う)

加えて、現代の多くのプログラムではネットワーク通信を扱うことが多いと思いますが、というかHTTPを扱うと思いますが、HTTPASCIIをベースとしつつバイナリも混ざる混沌とした世界です。言い換えるとバイト列なのに文字列処理をしたいというワイド文字としては扱いづらいデータになります。(byte[]とStringの相互変換が乱れ飛ぶコードを目にした人も多いのではないでしょうか)

結局の所、ワイド文字という試みは失敗であったし、今となっては無意味な複雑化であると結論づけていいのではないかと思います。

Ruby の選択

Ruby はマルチバイト文字型のアプローチを採用しています。(「Unicode路線に見切りをつけ」たのではなく、ワイド文字路線に見切りを付けたのである)これにより、String#each_byte, String#each_char, String#each_codepoint などのメソッドを通じて、バイト列上に構築された様々な抽象化レイヤを自在に扱うことが出来ます。また、現在は要望やユースケースが皆無なために実装は見送っていますが、IVS を考慮した each 亜種も容易に追加することが出来ます。

加えて、複数の文字コードを同時に扱う…ことは普通の人はやらないと思いますが、ネットワークプログラミングを行う際にバイト列と文字列シームレスに扱うことが出来ます。つまり、HTTPヘッダ等を扱う際にbyte[]とStringを変換する必要がありません。

まとめ

ワイド文字はオワコン

shinichiro_hshinichiro_h 2014/11/07 20:27 素人質問なんですが、結合文字て概念は筋が良いものだったんでしょうか。

nursenurse 2014/11/08 14:38 たぶんこれでも「筋がいい」ものなんじゃないでしょうか。

もちろん日本語やアルファベットの類ならば合成済みの文字を使った方が手っ取り早いんですが、
ハングルやデヴァナガリ文字のように、母音字と子音字が融合して一つの文字となり、
さらにそこにアクセント記号がついてくると合成済みの文字では辛くなってくるのではないかと思います。

ハングルは 子音 19 × 母音 21 × パッチム 28 = 11,172 文字を全て合成済み文字として収録していますが、
デヴァナガリ文字とかクメール文字はあれ有限なのかなぁ。
という具合なので、結合文字を避けて、合成済み文字の収録に走るのも一苦労です。

そもそも、実際の文字処理を考えていくと、
* 組版:アラビア文字やデヴァナガリは、結合文字ごとき誤差というくらいどうあがいても地獄
* 文字列置換:どっちもおなじ
* 検索:どのみち正規化とかが必要
* 比較:どのみち正規化とかが必要
* ソート:どのみちめんどい
* 文字数カウント:結合文字があるとテーブル引く必要があるけれど、本当に欲しいのはバイト数とかじゃないですか?
という具合なので、ワイド文字の幻想が壊れる以上のインパクトは実は無いような気がします。

結局の所、なくてすむならない方が楽だけれど、結合文字を考慮しないといけないような処理はどのみち地獄なので変わらん、と。

shinichiro_hshinichiro_h 2014/11/22 23:39 質問しておいて、質問したことを忘れてしまっていました。回答ありがとうございます!

合成済み文字の収録を、本当に列挙するんでなくて、機械的にする、ってのはナシなんですかねえ。この値からこの値まではこういう部品の合成文字が入りますよーみたいに宣言するというか。

本題のワイド文字がダメ、てのは、まあそんな気がするなあと思うのですが。

2014年04月16日(水)

Cの構造体や関数が定義された位置を表示するnadokabot、crubybotつくった 18:31 Cの構造体や関数が定義された位置を表示するnadoka用bot、crubybotつくったを含むブックマーク Cの構造体や関数が定義された位置を表示するnadoka用bot、crubybotつくったのブックマークコメント

なにをつくったか

表題のとおり crubybot.nb ですが、その名の通りCRubyのソースを解釈して、与えた構造体や関数の定義位置を返します。返す時はGitHubURLなんですが、まぁそこは枝葉ですな。

libclang

Cコンパイラにはプリプロセッサ構文解析構文木の構築などが含まれています。ですので、Cソースで何かをしたい場合、Cコンパイラモジュールを使えると便利です。clang由来の便利なやつがlibclangです。

なにをしているか

find_def のあたりを見ればわかるでしょ。

まとめ

というわけで、libclangを使うと簡単にCソースで遊べるので便利です。

付録

きつねさんとおぼえる!Clang おかわり を読んだらもっと楽にできた気もするけれど、わたしは読めていません。

トラックバック - http://d.hatena.ne.jp/nurse/20140416

2014年03月17日(月)

最近のFreeBSDのsignal trampolineの場所 03:58 最近のFreeBSDのsignal trampolineの場所を含むブックマーク 最近のFreeBSDのsignal trampolineの場所のブックマークコメント

しばらく悩んでしまったので、後世の人が悩まないように。

プロセスにシグナルが送られると、カーネルはsignal frameをスタック(またはsigaltstack)に積み、「signal handlerを呼び、戻ってきたら後片付けをして元々のプログラムの位置に戻る関数(=sigreturn)を呼ぶコード」を実行します。詳しくは「インタプリタとシグナル - 微酔半壊」で。

で、このコードが signal trampoline なわけですが、backtrace で得られるアドレスにもこの signal trampoline 内を指すアドレスがあります。具体的には signal handler を呼んだ直後のアドレスです(理由はDEBUG HACKSのHACK #27あたりで)。なので、FreeBSD amd64 の場合 sys/amd64/amd64/sigtramp.S がどこに置かれたか探すわけですが、sys/kern/kern_exec.c だけを見ていると実際の値といまいちずれることがあります。

理由は r217151 にて shared page なるものが導入されたからです。酷いのは、実際に確保される場所が場合によって違うっぽいことで……、http://lists.freebsd.org/pipermail/freebsd-current/2013-November/046773.html:title=ある報告では0x00007ffffffff003だと言っているけれど」、手元では0x00007ffffffff193なんですよね……。

この問題は、r258661で実際に signal trampoline が置かれた場所を sysctl で取れるようになるようなので、それを待てば良いということになります。work around が必要ならば、shared pageの始まる0x00007ffffffff000以降のどこか、ということになりますが、まぁいいよね。

トラックバック - http://d.hatena.ne.jp/nurse/20140317

2014年03月07日(金)

C backtrace 22:04 C backtraceを含むブックマーク C backtraceのブックマークコメント

5. Backtrace系ライブラリについて。

> シグナルトランポリンとかよくわからないので教えてほしい。

わたしは黒のBSD本 (4.7 Signals) で勉強しました。日本語訳は入手困難だけど、英語版ならKindleで買えます。

が、第2版が8月にでるそうです!(3月14日追記)

> CRubyにもどっかから持ってきたのかaddr2line.cってやつがあって、さっきのexecinfo.hで得た情報をもとにして、更にDWARFのデバッグ情報をつかって情報を拾い集めている。

経緯は %ruby観察日記 2010-11-25#4089 にありますが shinh さんによる独自実装ですね。

なお、Rubyの場合、rb_print_backtrace() という C API が(非公開APIとして)存在します。

ので、デバッグ用ではご自由にお使いください。

公開するgemでは使うなよ!ゼッタイだぞ!!

トラックバック - http://d.hatena.ne.jp/nurse/20140307

2014年02月12日(水)

さくらのBASE Storage について 15:18 さくらのBASE Storage についてを含むブックマーク さくらのBASE Storage についてのブックマークコメント

待望のs3っぽいやつがさくらに来たので、chkbuildのログ上げてみたら、CentOS系だけで70GB近くあった。 http://logfiles.b.storage.sakura.ad.jp/

content-typeとHTTPヘッダ (Content-Encoding) の設定ができないので、html.gzやtxt.gzをブラウザに自動展開してもらえないのが困っている。

トラックバック - http://d.hatena.ne.jp/nurse/20140212