「文字列を文字の列とみなす単純化」ってどういうこと?解説編

先日 @shyouhei さんのTweetに反応して文字列が文字の列かどうかが言語によって異なるという話をTweetしました。

shyouheiさんの投稿:

PythonはどうかしらんがRubyの設計思想は「世の中はシンプルじゃない」だからな。文字列を文字の列とみなす発想その物がすでにRubyからすると過度に世界を単純化しすぎている。

https://twitter.com/shyouhei/status/528106973565165568

もうちょっと言っておくと数値計算で勝ち目のないRubyは文字列処理にめっちゃ注力してるんで。文字列処理こそがRubyの主戦場。そこでRubyが文字列をあえてカタマリで扱ってることにはそれなりの理由というものがある。つまり分解しようとするほうが困りごとが増える。IVSとか。

https://twitter.com/shyouhei/status/528108890152386560


僕の投稿:

世の中にはJavaPythonのような文字列を文字の列と考えてる言語と、そうではないRubyのような言語とがある、言語によって文字列の設計自体が違うんだ、ということはもっと知られてよいと思う。拙著コーディングを支える技術では五つの言語で文字列の設計を比較してる(ad)

https://twitter.com/nishio/status/529105331511492608


これに対して「えっ、文字列って文字の列じゃないの?!」という反応がいくつかあったようなので、補足説明しておきます。

文字列に対する一番素朴な考え方は「8bit(0〜255)の値の配列」というものです。これを「文字の列」と考える人もいるでしょう。しかし、その考え方だと、ひらがなの"あ"は文字ではないことになります。しかたがないので、複数文字を特定の並びにした時には"あ"と解釈するという決め事をしたりしました。でも、これは不便でした。

そこで、ひらがなとか漢字とかも1文字だと考え、それぞれに16bitの数値を割り振ろうと考えた人たちがいました。そうやって出来たのがUnicodeです。この方法なら「文字列は(文字=16bit)の列だ」とシンプルになります。PythonJavaも文字列を文字の列として扱います。なので1文字取り出したりするのがとても簡単です。めでたしめでたし。

ところが残念ながら世界はそんなにシンプルではなかったのです。「そもそも16bitの6万個程度では漢字を全部表現するのに足りないよね」「異体字はどうすんの」「"が"は単体で1文字なのか、"か"に濁点が付いているのか」「携帯のメール本文に顔文字が入れられるけど、これも文字だよね」「顔文字の顔の色の選択肢に黒がないのは差別だ!」などなどいろいろな問題が噴出しました。

Rubyは早々にUnicode路線に見切りをつけて「8bitの列に、それがどういう符号化の方式かの情報をセットにしたもの」を文字列だと定義する独自路線を取りました。筆者はこの設計の違いが影響するような仕事をしたことがないのでよくわかりませんが、Rubyだとなんか色々楽になるらしいです。

拙著「コーディングを支える技術」では、p.150から「文字とはなにか」という話が始まり、このあたりの話をもう少し詳しく書いてから5種類の言語で文字列の設計がどう異なっているかを解説しています。

追記

こういうのどこで知るの?という疑問があるようです。どこで知ったかは忘れました。るびまかな?でも、少なくともマニュアルには書いてあるはずだよね、と思ったので調べてみました。

Javaはこう書いています。UTF-16を使って、16bitで収まらない文字についてはサロゲートペアを使うとのことです。

A String represents a string in the UTF-16 format in which supplementary characters are represented by surrogate pairs

http://docs.oracle.com/javase/7/docs/api/java/lang/String.html


PythonUnicode code pointの列だとしか書いていません。ちょっと不親切です。

Strings are immutable sequences of Unicode code points.

https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str


これは、大昔(2001年リリースのPython2.2)から16bitと32bitをコンパイルオプションで選べる仕組みになっているからです。

Python 2.2 will allow the 4-byte implementation as a build-time option. Users can choose whether they care about wide characters or prefer to preserve memory.

http://legacy.python.org/dev/peps/pep-0261/


一方Rubyはbytesの列だ、と書いています。

A String object holds and manipulates an arbitrary sequence of bytes, typically representing characters.

http://www.ruby-doc.org/core-2.1.4/String.html

追記

補足頂きました。

ちょっと目を離した隙に @nishio さんが俺の投稿をマクラにして書籍のステマをしていたようだが、声を大にして言いたいのはそもそもUnicode文字列は定義から言って文字の列ではない。Unicodeには「非字」が含まれているからだ。 http://www.unicode.org/faq/private_use.html#noncharacters

https://twitter.com/shyouhei/status/530601364225679360

詳しい解説をトラックバック頂きました。 http://d.hatena.ne.jp/nurse/20141107#1415355181