In article <48D39C4D.1000109 / airemix.jp>,
  "NARUSE, Yui" <naruse / airemix.jp> writes:

> いまいち理解しきれていないのですが、
> 文字の最初のコードポイントがエスケープ対象だったら常にエスケープする、
> ということで対処できませんか。

エスケープはコードポイント単位で行う、と定義すれば対処はでき
ます。

ただ、String#inspect だけであればそう実装すれば済みますが、
エスケープの類は Ruby レベルでも多々実装されていて、そこで
grapheme cluster 単位で動作する正規表現は使えなくなります。

もし使ってしまうと、(実際、現実のコードで使われているわけで
すが) 奇妙なことが起こります。例えば、「"」 を「""」とエスケー
プするというルールがあったとして、str.gsub(/"/, '""') という
コードを書いたとすると、「" + 濁点」のエスケープに失敗します。

また、REVERSE SOLIDUS を前置するとか、上記の QUOTATION MARK
を倍増させるエスケープなら grapheme cluster は変化しないので
すが、grapheme cluster が変化してしまうエスケープもあります。
「*」を「\x2A」に変換すると、「* + GRAVE」は「\x2A + GRAVE」
になるかもしれません。ここで GRAVE は直前の A に結合するので
「A + GRAVE」という元の文字列とはなんの関係もない文字が出て
きます。
(さらに、だれかが NFC に変換すると、「A + GRAVE」はひとつの
コードポイントになって、「\x2(A+GRAVE)」になるかもしれません。
そうすると、アンエスケープするにはまず NFD に変換して... ちょっ
とかんべんしてください)

これらを避けるにはやはりエスケープは文字の単位で行うのが妥当
でしょう。コードポイント単位で行うというのは Shift_JIS をバ
イト単位でエスケープした「表\」のようなものです。

しかし、そうすると、結合文字は Unicode の成長にしたがって増
えていくので、外部から来た文字列に、ruby が知らないコードポ
イント (ruby が知っている Unicode では文字が定義されていない
コードポイント) があった場合、この扱いには注意が必要になりま
す。

外部は、より新しい Unicode のバージョンを知っていて、そのコー
ドポイントが結合文字として扱われることを期待しているかもしれ
ません。とすると、その直前のコードポイントが文字列の終了を示
す QUOTATION MARK だったとしても、外部は文字列はそこでは終了
しないと考えているかもしれません。おそらく安全のためにはその
ようなコードポイントがあったら外部との通信を打ち切らざるを得
ないでしょう。

もちろん、Unicode のバージョンをネゴシエーションして、情報の
送信側と受信側が文字の定義に関して合意すれば問題はおきません
が、それを行うのはさらに準備が必要です。

> 階層が バイト列 > コードポイント列 > graphem cluseter列 となり、
> each_char は「graphem cluster」を対象とするようになるだけで、
> エスケープのような低いレイヤーには影響がないようにも思えるのですが。

必ずしもエスケープが低いレイヤで動作するとは思いません。
-- 
[田中 哲][たなか あきら][Tanaka Akira]