タグ「Unicode」が付けられているもの

仮名合字・合略仮名の文字コード

合字とは

合字というものがあります。複数の文字を組み合わせて一文字となったものです。欧文の「Æ」のような文字はどこかで見たことがある人が多いでしょう。いうまでもなくAとEの組み合わせです。ドイツ語の「ß」も「ss」を表す合字です。合字を英語ではligatureといいます。

漢字にも,「麻呂」を組み合わせて一字になった「麿」や,「久米」の「粂」等の合字があります。

仮名文字にも合字があります。今日,通常の文章には用いられませんが,昔のものには見ることができます。こうしたものは仮名合字や合略仮名と呼ばれます。

ここではそれらのうち,現在符号化されているものについて文字コードをまとめてみます。

仮名合字の文字コード

文字読みJIS X 0213UnicodeUnicode文字名Unicodeブロック
より1-2-25U+309FHIRAGANA DIGRAPH YORIHiragana
コト1-2-24U+30FFKATAKANA DIGRAPH KOTOKatakana
𪜈トモU+2A708(CJK)CJK統合漢字拡張C
𬼀シテU+2CF00(CJK)CJK統合漢字拡張F
𬼂なりU+2CF02(CJK)CJK統合漢字拡張F

最後のものは合字ではなく「也」の草体からきたもので,仮名のように扱われるそうです。

これらのうち最も早く取り入れられたのは,JIS X 0213:2000にて符号化された平仮名合字より,片仮名合字コトです。それに基づいてUnicodeにも入りました。

Unicodeで漢字扱いされているものがあります。ものによっては,仮名合字でなく漢字の草体としてみなされるものもあるようです。

これで全てではなく,今後符号化されるものもあるかもしれません。

用例

「エンジニアHub」にて記事を執筆しました。「文字コード再入門 ─ Unicodeでのサロゲートペア、結合文字、正規化、書記素クラスタを理解しよう!」として公開されています。

若手エンジニア向けのWebメディアとのことで、プログラミング上の注意点にフォーカスした内容になっています。コード例にはJava, Python, Rubyを用いています。

拙著をすでにお読みの方には復習となる内容ですが、まだの方はこの機会に是非お読みいただければと思います。記事の最後に拙著『[改訂新版]プログラマのための文字コード技術入門 (WEB+DB PRESS plusシリーズ)』の版元へのリンクも設定されていますので、興味を持たれた方には書籍の方もお読みいただければ幸いです。

当記事編集担当の方には「とても品質の高い記事」とのことで感謝のお言葉をいただきました。読者のお役に立つことを願っています。

Unicode 10.0リリース、変体仮名を収録

Unicode 10.0が2017年6月20日にリリースされました。今回は8,518文字が追加されています。

日本語話者にとって最も関係しそうなのは変体仮名の導入でしょう。

変体仮名とは

現在、平仮名は1音につき1文字ですが、以前は同じ音に対して複数の書き方がありました。例えば、平仮名の「か」は漢字「加」が元になっているもので、これ以外に「か」と読む平仮名はありませんが、かつては「可」を元にした仮名も使われていて同じく「か」と読まれました。そうした複数のバリエーションがあった仮名を明治時代に標準化したものが今の平仮名です。このとき採用されなかった異体が変体仮名と呼ばれるものです。

変体仮名は今日では文章を綴るのには使われませんが、そば屋の看板などで装飾的に用いられることがあります。

Unicodeにおける変体仮名

変体仮名はUnicodeではBMPでなく面01に配置されました。U+1B000-1B0FFのKana SupplementブロックおよびU+1B100-1B12Fの Kana Extended-Aです。例えば先ほど例に挙げた「可」に基づいた「か」は符号位置U+1B019にあり、文字名はHENTAIGANA LETTER KA-3とされています。読みを「KA」のように示して、複数ある異体は数字で区別されています。全部で285文字の変体仮名が収録されています。

符号化の方式としては、単純にひとつの符号位置にひとつの文字が対応する形になっています。複数の読まれ方をする字がありますが(例えば「惡」に基づく字、「あ/を」)、こうしたものもひとつの符号位置にのみ置かれ、読みが違うからといって重複して配置されてはいません。標準化の途中の段階では、音価に相当する符号位置を与えて異体字セレクタのようなもので変種を示すといった案もあったようですが、最終的には扱いやすい形式に落ち着いたことになります。

漢字の追加も

今回、CJK統合漢字拡張Fが追加されています。7,473文字と結構大きな追加です。使う機会があるかどうかはまた別の話ですが......。

拡張Fのコード範囲は2CEB0-2EBE0となっています。

Pythonとlibiconv, nkf, Javaのコード変換を比較した記事がありました。

ASCIIとJIS X 0201の違いに起因する円記号問題とチルダ・オーバーライン問題、それにUnicodeのFTPサイトが原因と思われる全角ダッシュの件という既知の問題が多いので目新しくないのですが (『プログラマのための文字コード技術入門』をお読みいただければわかります)、Pythonについて目新しげな話がありました。

Pythonでは他と違って、二重(白抜き)の括弧をU+FFxxの位置にあるものでなくU+29xxに割り当てているそうです。うむ。そうか、そうきたか。

JISの公式な対応表ではU+FFxxの方になっています。文字名でいうとFULLWIDTH {LEFT|RIGHT} WHITE PARENTHESISです。

ただ、ここで「なぜFULLWIDTHなのか」という疑問を持った方もいるでしょう。本来UnicodeのFULLWIDTH/HALFWIDTH云々というのは、シフトJISのように1バイトコードと2バイトコードとの間で重複符号化のある符号化方式との往復変換の救済用に設けられたものです。ところがこの括弧記号はJIS側の符号化方式(Shift_JISやEUC)で重複符号化されているものではないので、本来FULLWIDTHになるきちんとした理由はありません。にもかかわらず、UnicodeにJIS X 0213の文字を追加する作業でなぜかFULLWIDTHの方に入れてしまいました。

一般に用いられている変換表は、(多少ヘンだと思ったかもしれないにせよ)このUnicodeの作業を反映したものになっています。JIS X 0213の追補1でもそうなっています。Pythonのような判断をしたものは私はほかに見たことがありません。

Pythonがこうしたのは、強い信念のもとでの判断なのか、そうでなく何か行きがかり上そうなっただけなのか、ちょっと興味を惹かれるところではあります。

UnicodeにはのちにU+2E28, 2E29に{LEFT|RIGHT} DOUBLE PARENTHESISというのが追加されて(バージョン5.1らしい)、どうもこっちがいいんじゃないかという気もしてくるのですが、後から出してこられるのはつらい。3.2の時にあれば良かったのですが。

ちなみにこの二重の括弧は、文章や辞書において文中に入れる注記の類に用いられることのある記号です。

【追記 2017年6月7日】 JISとUnicodeの間のコード変換表はこちらから入手できます。JISの公式な定義と同等です: JIS X 0213のコード対応表

札幌で見たJIS X 0213の文字

札幌の中心部、大通公園と札幌駅を地下でつなぐ地下歩行空間を歩いていたら、パフォーマーが芸をしていました。その背後の柱に、JIS X 0213の文字が書かれているのが見えました。これはパフォーマーとは無関係にもともと書かれているものだと思います。次の写真です。

irankarapte

「イランカラㇷ゚テ」と書かれています。これはアイヌ語の挨拶です。写真には写っていませんが、他の柱には他の言語の言葉が書かれています。いろいろな言語が書かれているうちの一つです。

アイヌ語用の片仮名と文字コード

この中の小書きの「ㇷ゚」という文字は、もともと広く使われている日本の文字コード規格JIS X 0208になく、その拡張規格のJIS X 0213で符号位置が与えられたものです。漢字集合1面の、6区88点にあります。この文字は子音pの後に母音が続かない時に使われるもので、アイヌ語表記には頻出します。拙著『プログラマのための文字コード技術入門』では、アイヌ語で魚を意味する「チェㇷ゚」という語を題材として、符号化の例を示すのに使いました。

日本の文字コード規格は日本国内の言語表記に用いられる文字に対応しているべきですが、JIS X 0208は日本国内の言語であるアイヌ語に十分対応できておらず、ウェブサイトではfontタグを使って「プ」を小さくするような間に合わせの手段を強いられていました。日本国内の文字に不足があるというJIS X 0208の欠点を改善するJIS X 0213が規格化されて初めて、アイヌ語テキストの符号化が可能になりました。

なお、Macではアイヌ語の入力方式が日本語とは別に用意されています。これを使うと、「irankarapte」と打鍵すると「イランカラㇷ゚テ」と入力されます。

Unicodeではどうか

JIS X 0213の規格化を受けて、Unicodeにもアイヌ語用の片仮名が追加されました。ただし、結合文字を使って2つの符号位置の連続で表現できる文字については単独の符号位置が与えられませんでした。この「ㇷ゚」もその一つです。Unicodeでは、半濁点のつかない「ㇷ」の直後に合成用半濁点U+309Aを続けることで「ㇷ゚」を表現します。ちなみに半濁点のつかない小書きの「ㇷ」はアイヌ語の樺太方言の表記に使われるそうです。

この言葉の意味について

このイランカラㇷ゚テという言葉はアイヌ語の挨拶ですが、改まった感じのときに使われるものだそうです。この言葉については以前書いたことがあります。興味のある方はご参考に。

いつでも、どこでも、問題なく使えるように

この文字はJIS X 0213にあるので、Shift_JIS-2004, EUC-JIS-2004という符号化方式で問題なく使えます。今や、SJISというときはShift_JIS-2004、EUCというときはEUC-JIS-2004を使うことが必要です。そうでなければここで挙げたアイヌ語表記用の文字は使えません(CP932は論外)。

もちろん、Unicodeでも符号化できますから、UTF-8やUTF-16あるいはUTF-32でもOKです。ただし、結合文字で問題が出るようではいけません。つまり、「1文字=1符号位置」という前提のプログラムは駄目です。

アイヌ語表記用の文字に限らず、日本語ローマ字に使われる āīūēō のような長音符号つきのアルファベットや、尾骶骨の「骶」(1-94-21)、高校の教科書にある璦琿条約の「璦」(1-88-30)、リオ五輪の中国卓球選手・許昕の「昕」(1-85-14)、部首・字体記述要素の「亻」(人偏、2-1-21)、「礻」(示偏、2-82-64)、「灬」(列火、2-79-56)などなどの第3第4水準漢字が使えないのは日本の文字の符号化としてあまりに制約が大きいので、常にJIS X 0213の文字に対応した符号化方式を用いる必要があります(参考: 第3第4水準文字コードを使おう!)。フォントもJIS X 0213の全文字に対応したものを用いることが必要です(参考: 第3第4水準フォントを使おう!)。

生前譲位の報道でUnicode仕様書の元号の問題を思い出す

天皇陛下が生前譲位される御意向という報道が出回り、様々な意見や憶測が飛び交っています。その中には譲位がなされれば行われるであろう改元についてのものもあります。これで私が思い出したのはUnicode仕様書の中の元号の説明が微妙に間違っている件です。

平成は1989年1月8日から始まりましたが、Unicode Standardの説明では1月7日としており1日ずれています。昭和や大正もなぜか同じく1日ずれています。アメリカ時間でもないのでしょうが、不思議な現象です。

Unicodeの最新版ではどうか?

上の記事を書いた時はUnicode 6.1だったのですが、現行の最新版ではどうかとチェックしてみました。

先日Unicode 9.0が発表されましたが(参考: Unicode 9.0が出ています (2016年6月))、上記記述に対応する部分のPDFはまだウェブサイトで公開されていません。"Available August 2016" と記されています。

現在該当部分を確認できる最新版は8.0.0でした。Chapter 22 Symbolsの中、Table 22-8 "Japanese Era Names" が該当部分です。これを見ると、先の記事を書いたときと同じ記述になっていました。仕様書の以前の版の記述をそのまま持ってきただけなのでしょう。誰も気づいていないのかもしれません。

元号の合字のようなものについて

なお、UnicodeにはU+337BからU+337Eの範囲に、明治から平成までの元号を1文字分にした合字のようなものが割り当てられています。これの存在が上記Table 22-8の設けられた理由です。

改元によってこれらに加えて新たな元号のものが追加されると思う向きもあるかもしれませんが、これら4つの元号の符号位置は元来ベンダ定義外字との互換用に設けられたものなので、新たな元号を追加するというのは適当でないでしょう。最近では知らない人もいるのかも知れませんが、昔のPCではベンダがシフトJISなどの文字コードの空き領域に勝手に文字を割り当ててしまうという問題があっていまだに尾を引いていますが(現在ではJIS X 0213やUnicodeの文字コード標準に従うべき)、その中にこれらの元号もあったのです。当時想定されたのがスペースの節約のためか縦書き用か詳細は知りませんが、いずれにせよ1文字分に詰め込みたいなら組版の機能で行うべきです。

もし個々の元号について必要だというなら、西暦645年の大化から明治の直前の慶応まで、全部の元号を追加すべきということも言えてしまうでしょう。

Unicode 9.0が出ています

UnicodeコンソーシアムからUnicode 9.0が6月21日に出ました。

このバージョンではちょうど7,500文字が追加されたということです。数がずいぶん多いようにも思えますが、多くは西夏文字で、6,881文字あります。この数字はブロックTangut, Tangut Components, Ideographic Symbols and Punctuationの字数の合計です。

西夏文字についてはひとつ前の記事に書きました。

ISO/IEC 10646とUnicodeが同期するように更新というのはこういうことで、10646に追加された西夏文字がUnicodeでも追いかけるように追加されているわけです。逆、つまり先にUnicodeに入って後から10646に追加されるものもあります。先の記事のCJK統合漢字の追加9文字というのはUnicodeでは昨年のバージョン8.0で入ったものです。またU+301C波ダッシュ (WAVE DASH) の例示字形の修正もUnicodeではバージョン8.0で行われていました。

文字の追加に応じてUnicodeの文字情報を収めたテキストファイルUnicodeData.txtも当然更新されていますが、西夏文字については各文字について1行ではなく、漢字と同じようにコード範囲を示す形になっています。具体的には、「<Tangut Ideograph, First>」で範囲の最初が示され、次に「<Tangut Ideograph, Last>」で終わりが示されています。漢字のほかにも私用領域(PUA)やサロゲート領域を示すのにも同じ形式が使われています。

Windowsのメモ帳でテキストファイルを保存するときに文字コードを選択できますが、その選択肢では「Unicode」と「UTF-8」が並列に置かれています。これに違和感を持つ人も少なくないでしょう。このことを強い調子でけなしている文章をネット上で見かけたので、ちょっとこの件について書いてみましょう。

実はここで「Unicode」と言っているのはUTF-16のことです。現在多くの人は、「Unicodeの符号化方式としてUTF-16やUTF-8がある」ものと理解しているでしょう。拙著でもそう説明しています。するとWindowsのメモ帳の開発者はUnicodeを分かっていないのでしょうか。いえ、そうとも限りません。

過去の経緯

Unicodeは元々、16ビット固定長の文字コードとして開発されました。ASCIIが7ビットで1文字を表すのと同じように、Unicodeは16ビット版のASCIIですよ、エスケープシーケンスやSI/SOのような制御文字で文字集合を切り替えたりしないシンプルな文字コードですよ、という触れ込みだったのです。Unicode 2.0の仕様書でもそう説明されていました(過去記事参照: 「文字数制限」)。

しかし、のちに、最大65,536文字までしか表せない16ビットでは不足ということになり、サロゲートペアによって拡張するUTF-16が考案されたり、当初無意味だったUCS-4がBMP以外の面への文字の割り当てによって存在意義を持つようになったり(UTF-32)、はたまたASCIIと互換性のあるUTF-8がよく使われるようになったりして、「Unicode = 16ビット固定長」では具合が悪くなりました。それで「16ビット固定」のような言い回しはいつの間にかやめて、現在のような形になっています。ちなみにUnicode 8.0仕様書ではUTF-16の "origin" について、「UTF-16 is the historical descendant of the earliest form of Unicode, which was originally designed to use a fixed-width, 16-bit encoding form exclusively.」(2.5 Encoding Forms)と説明されています。

なので前世紀に書かれた文書やプログラムでは「Unicode = UCS-2」という前提があり、それを漫然と引き継いでいると、「Unicode」と言っているのが実質的にはUTF-16を指していることがあるわけです。

そして現在

今では個別の符号化方式としては「UTF-16」「UTF-8」のように言った方が適切なことは言うまでもありません。ただ、UTF-16の意味で「Unicode」と言われることがあるのは、単なる無知や誤解ではなく、それなりに過去の経緯が影響しているのだということです。

おわりに

なお、ここでは用語の説明などちょっと端折っているところもあるので、背景等含めて知りたい方は拙著をお読みいただければと思います。最後は宣伝?

箱根駅伝で楽しむ文字コード

発端は1月2日、箱根駅伝の最中の @mashabow さんのこのツイートでした。

そこで思い付いたのが以下の一群のツイートです。幸いご好評をいただいたので、少し解説を添えてここにご紹介しましょう。

1区1点、和字間隔、いわゆる全角スペースです。Unicodeに対応する文字名はIDEOGRAPHIC SPACE。この字はASCII相当のSPACEとの重複符号化とはされていません。理由は確か、ISO/IEC 2022の枠組みでSPが現れ得るのは8ビット符号表の2/0か10/0 (ビットパタン0x20と0xA0)に限られるからだったじゃないかという記憶がありますが正確なところは把握していません。

1区29点、ダッシュ(全角)。文字名EM DASH、Unicodeの符号位置はU+2014なのですが、隣のU+2015 HORIZONTAL BARに間違われることがあります。多分、昔Unicode ConsortiumのFTPサイトで配布されていた(obsoleteな)変換表でこの点を誤っていたためだと思います。位置が隣り合っているし字形も似ているので間違われやすいんでしょうね。

1区33点、波ダッシュ、WAVE DASH。「国際団体の名簿に......」というのは、Unicode仕様書の例示字形が最近までひっくり返っていたことを指しています。FULLWIDTH TILDEへの文字化けネタを出しても良かったのですが、他の文字とネタがかぶるのでやめました。

1区34点。双柱、DOUBLE VERTICAL LINEの名の通り、二つの垂直線なのですが、Unicodeへの変換で数学の平行記号に誤って移してしまうものがあります。平行記号はフォントによって直立だったり斜めだったりすることがあるので、斜めのものが使われると、垂直な線のつもりで入力した記号が斜線になってしまって、大層具合の悪いことになります。

1区61点、負符号、MINUS SIGN。JIS X 0208はASCIIやISO/IEC 646と異なり、マイナスとハイフンのそれぞれの記号に独立した符号位置を与えています。ASCIIの「マイナスにもハイフンにも使われる記号」はUnicode/10646で「ハイフンマイナスという記号」だ、ということにされました。2000年に制定されたJIS X 0213は、互換性のためにこの「ハイフンマイナスという記号」を追加しています。それが「2000年大会から......」の意味です。

ツイートは以上です。本当はほかにも「4区から5区へのタスキリレー、平仮名が次々と片仮名に置き換わっていきます」とか、「2区、2000年大会から参加、二人で一人の『くの字点』兄弟」とか、やろうと思えば色々できたのですが、あまり多くてもくどいと思うのでやめました。

なお、上のツイートに挙げたコード変換のトラブルについてさらに知りたい方は拙著「プログラマのための文字コード技術入門」の第8章をご参照いただければと思います。

Unicodeサポートの現状

最近のJavaの更新版のリリースノートを見ていたら、こういうバグが修正されているのが目にとまりました。

XML文書の構造を変換するXSLTの実行において、部分文字列を得る関数にBMP外の文字を与えると結果が正しくないという話です。サロゲート1個を1文字分として勘定した結果になってしまうというものです。今年の3月に報告されています。

いかにもありそうなバグです。2015年になってもまだこういうバグが出てくるのだなあという感想を持ちました。

先日、拙著「プログラマのための文字コード技術入門」のEPUB版に関して、Unicodeで結合文字を用いる必要のある文字がEPUBの処理環境でうまくなくてPDF版よりも提供が大幅に遅れたということを書きました。サロゲートだけでなく結合文字についても、というか多分こちらの方がより長く(あるいは多く、またはその両方)、トラブルが続きそうに思えます。

悲観的にいえば、Unicodeあるいはその処理環境が今と同じ仕組みであれば、こうした種類のトラブルは半永久的に続くのかもしれません。

拙著「プログラマのための文字コード技術入門」の電子書籍版、既に提供済のPDF版に加えて、EPUB版の公開が開始されたようです。

PDFが先行して販売されていましたが、EPUBはUnicode特有の問題のために時間がかかっていたようです。

本書の原稿はJIS X 0213にある文字だけを使っているのですが(EUC-JIS-2004で書いたので当然)、Unicodeで符号化したときにアプリケーションの処理で問題になりそうな点として、サロゲートペアの必要な文字、結合文字の必要な文字、互換漢字、という3つが挙げられます。今回のEPUB (のアプリケーション)では主に結合文字の箇所で問題があったのではないかと思います。そういうところはまさに本書が扱っている文字コードの問題です。

ともあれ、EPUBで読みたい方はぜひ試してみて下さい。上記リンクではPDFとEPUBのセット販売となっています。

Unicode 8.0リリース

Unicode 8.0が2015年6月17日に出ました。

日本での使用に関係しそうな主な変更内容をあげると、

などでしょうか。トータルでは7,716文字増えたそうです。

個人的には、絵文字は正直、そこまでするならいっそ画像でやったらどうですか......という印象もあります。LINEのスタンプとかね。

上記リンク先の末尾には、漢字のデータにおいて、日本ソース(kIRG_JSource)として古いJIS X 0212やベンダ定義漢字の代わりにJIS X 0213への参照を使用するようにしたという記述が見えます。

ついでに、「Changes for Deprecation of Language Tags」という謎の説明があります。タグ文字U+E0020〜U+E007EがDeprecated=True から Deprecated=False に変更されたと。正直、使う気がしないので真面目に追いかけるつもりはないのですが、興味の湧いた方は調べてみて下さい。

Unicodeの新しいバージョンに従ったテキストデータがきちんと処理できるようになるためには、単にフォントがあるだけでなく、文字の属性データが最新版に更新される必要もあります。例えばJava 8では文字の情報はUnicode 6.2によっています。こうしたところの対応は徐々に進んでいくでしょう。

Unicode 8.0では、U+301C WAVE DASH (波ダッシュ)の例示字形が変更されて、JIS X 0208/0213の1面1区33点の例示字形と同様の形になるそうです。UnicodeコンソーシアムのウェブサイトのBETA Unicode 8.0.0から確認することができます。

波ダッシュがシフトJIS等のJIS系の符号化とUnicodeとの間の変換で文字化けを生じるケースがあることは、拙著『プログラマのための文字コード技術入門』第8章で説明しました。Unicode仕様書の例示字形は問題の一部でしかありませんが、これが是正されることは良いことだと思います。

さて、上記『文字コード技術入門』は全8章とAppendixとからなりますが、波ダッシュ問題について記しているのは本編の最後である第8章です。この位置に置かれていることには理由があります。

それは、この問題をきちんと理解するためには、第1章から第7章までのほとんどの章の内容が関連してくるからです。コード表の例示字形やフォントにだけやたら詳しくても、あるいはコード変換プログラムの実装についてだけやたら詳しくても駄目で、全体像を理解する必要があります。

本書への書評に、第8章の記述についてそうした構成の意図を汲んで言及してくれたものがあって、ああきちんと読み取ってくれているのだなとありがたく思った記憶があります。(URLをなくしてしまったのでリンクできないのが残念ですが)

パラメータをちょっといじったら文字化けが直りましたといった刹那的な話ではなしに、文字コードとはそもそもどういうものであって、どんな背景にもとづいて何が起こっているのかを理解し、長期的に見てどうするのがいいのかを判断するために本書の説明が役に立てば幸いです。

プログラムのソースファイルに文字を記すときに、キーボードから入力できなかったりフォントがなかったりといった理由で、Unicodeの符号位置を使って記したいことがあります。最近の言語では似た形式でそうしたUnicodeエスケープを記述できますが、微妙に違いがあります。ここではJavaとPython, Rubyを比べてみます。

JavaのUnicodeエスケープ

Javaではバックスラッシュ(\)とアルファベットのuに続けて4桁の16進数でUnicode符号位置を記します。

例えば、\u4e00 とすれば漢字の「一」を記したのと全く同じことになります。

JavaのUnicodeエスケープはコンパイルの初期段階で処理されるものなので、文字列リテラルの中で改行を意味する \n 等とは扱いが異なることに注意が必要です。このことは『プログラマのための文字コード技術入門』第7章に記しました。

'\u' の後に記す符号位置は厳密に4桁しか解釈されないので、BMP外の符号位置は直接記すことができません。サロゲートペアの上位下位をそれぞれ \u を使って記す必要があります。これは面倒な話で、いまだにこれしかないというのが信じられないのですが、Java 8版のJava Language Specificationをざっと見たところではほかの手段はなさそうです。(見落としてるかなぁ...)

PythonのUnicodeエスケープ

Pythonにも同様の記法があります。'u' の大文字小文字2種類があります。小文字の \u は16進4桁、大文字の \U は16進8桁で記します。例えばこうなります:

>>> print u"\u9bd6"
鯖
>>> print u"\U00029e3d"        ←BMP外の符号位置、魚の「ホッケ」の漢字
𩸽

(Python 2.7.5で動作確認)

ここで横着して頭のゼロ3つを省いてしまうとエラーになります。8桁というのは無駄な感じもしますが(ISO/IEC 10646の符号空間は以前は4バイト分ありましたが、今はUTF-16の範囲に限定してしまったので6桁で十分)、Javaと違ってサロゲートの値を使わずに済むのはいいですね。

RubyのUnicodeエスケープ

Ruby 1.9以降では、 \uXXXX という形と、波括弧を付けた \u{XXXX} という2種類が使えます。前者は4桁限定、後者は5桁・6桁でもOKです。

irb(main):013:0> print "\u9bd6"
鯖=> nil
irb(main):014:0> print "\u{29e3d}"
𩸽=> nil
irb(main):015:0> print "\u{9bd6 29e3d}"
鯖𩸽=> nil

(Ruby 2.0.0で確認。nil云々は無視して結構です)

波括弧を付けない記法で例えば \u29e3d のように5桁記してしまうと、"\u29e3" + "d" のように扱われてしまいますから、こうしたときは波括弧を用います。

最後の例のように、波括弧を使う記法ではスペースで区切って複数の符号位置を並べることができます。

表外漢字UCS互換の憂鬱

下記のページに、「主権を?奪されて」というくだりがあって、頭の中で警報音が鳴り始めました。

「?奪」の「?」はHTMLソースから既に疑問符になってしまっています。何かが文字化けしてこうなってしまったのでしょう。

何が起こったのか想像する

前後の文脈から考えて、これは「剥奪」でしょう。もっといえば、「剝奪」だったのではないかというのが、私の想像です。何をいっているか、お分かりでしょうか。

「剥」と「剝」、両者は同じ字ですが、形の違いがあるのに気付いたでしょうか。左上の部分が「ヨ」のような形か「互」の上の横線が無いような形かどうかの違いです。

前者はJIS第1水準漢字(面区点位置1-39-77)ですが、後者はJIS第3水準(面区点位置1-15-94)、それも、JIS X 0213の2004年改正(JIS2004)で追加された「表外漢字UCS互換」10文字のひとつです。

上のウェブページでは、原稿に後者の「剝奪」を使ったところ文字化けしてしまったのではないかと想像します。MacでもWindowsでも「剝」を入力することはできます。

表外漢字UCS互換とは

「表外漢字UCS互換」というのは何かというと、『プログラマのための文字コード技術入門』第3章p.90でも説明していますが、簡単にいうと、印刷の字体としては「剝」の方がそれっぽくて好ましいのだけどもJISの例示字体は「剥」の方であった。そこで、JISの文字コード規格(X0213)の2004年改正の際に例示字体を変えたらいい、と考えた人がいたのだけど、Unicodeでは両者を区別し異なる符号位置を与えてしまっていて、JISの例示字体だけ変えると対応関係がうまくないことになってしまう。このため、JISでも以前からの「剥」とは別の符号位置に「剝」を用意することにした、というものです。こういうものが、この字を含めて10文字あります。

UTF-8やShift_JIS-2004, EUC-JIS-2004といった、JIS第3第4水準に対応した文字コードを使っている分には「剝」を使っていていもいいのですが、第1第2水準にしか対応していないJIS X 0208ベースのShift_JISやらISO-2022-JPなどに変換しようとすると、コード変換の実装にもよりますが上記の「?」のようになってしまいます。

上記のウェブページはUTF-8で符号化されているので「剝」を普通に文字として使うこともできるのですが、それでも「?」になってしまっているのは、もともと「剝奪」となっていた原稿を例えばメールで送信しようとしてISO-2022-JPを使ってしまったとか、プレーンテキストのファイルに保存するのに第3第4水準に対応していないコード(Shift_JISやその独自拡張の所謂CP932等)で保存してしまったとかいった事情があったのではないかと想像します。

常用漢字表の「剝」

ちなみにこの漢字は2010年に常用漢字表に入っています。例示されている字体は第3水準の「剝」の方です。ただし、手書きでは「剥」の形でもどちらで書いてもいいのですよ、ということが、常用漢字表では説明されています。

この字体差は手書きの楷書と明朝体活字との習慣の違いでしかないのであって、どちらでも同じ字です。正直これを文字コードで分ける意味は無いように思えますが、過去の経緯からしようがないという例のひとつだといえます。

JIS X 0213と常用漢字の各文字の対応は、JIS X 0213:2012で追加された附属書12に記載されています。

結局どうすればいいのか

JIS X 0213に含まれる文字を全部カバーしている符号化方式、例えばUTF-8やShift_JIS-2004, EUC-JIS-2004を常に使用していれば文字化けしません。現在なら常にUTF-8で困ることはあまりないでしょう。SJISやEUCの符号構造が必要な場合にはShift_JIS-2004やEUC-JIS-2004が使えます。

付記

リンク先のウェブページは、もしかすると全然違う理由で「?」になってしまっていて、元の字も実は「剝」ではなかった、という可能性はもちろんあります。推測ですのであしからず。

漢数字をソートすると

こんなブログ記事があって、面白く読みました。

「数字順にソートされない理由」はリンク先のブログ記事に書かれているとおりですが、「数の順にソートされないこと」が意外だということが、私には興味深く思えました。「漢数字」ではなく「漢字」ととらえれば、数の順に並ぶ必然性が特にないことは自然と納得されると思います。

文字コードにおける漢字の並び順

『プログラマのための文字コード技術入門』にも書きましたが、文字コード規格における漢字の並び順をちょっとおさらい。

  • JIS X 0208/0213の場合: 第1水準漢字は読みの順番、第2〜第4水準は(その水準内で)部首画数順
  • Unicodeの場合: 部首画数順 (ただし、順序はブロック内でしか通用しないので注意)

第1水準の読みの順番は、音読みが多いですが訓読みのものもあります。また、第3水準は第1水準の前や第1水準と第2水準の間にもあるので、単純にコードでソートするとおかしなことになります。さらに、JIS2004で第3水準に10文字追加された「表外漢字UCS互換」は、後から第3水準の隙間に詰め込んでいるので、これも例外となります。

またUnicodeの場合も、元々のCJK統合漢字ブロックと後から追加された拡張A, Bなんかをまたがると、コード順で整列した順序はデタラメになってしまいます。互換漢字があったりするとやはりうまくない。

対処の方針

文字コード順のソートは、あてにしないのが良いです。漢字の場合には特にです。例えばデータベースに格納されている人名のような場合は、読み仮名を別途持っておいてそれでソートする。

また、漢字以外でも、例えばアクセント付きのアルファベットを用いるフランス語やドイツ語等の欧州言語の場合にも文字コード順のソートというのはうまくありません。言語ごとの照合規則を用いる必要があります。JavaならCollatorクラスを使うとこれができます。『プログラマのための文字コード技術入門』p.257で紹介しています。国際的に使われるプログラムにはこうした考慮が必要となります。

余談

漢数字「一」「二」「三」に限ると、文字コード順のソートでは、JIS順でもUnicode順でも「一→三→二」になります。これはただの偶然の一致なのですが、ちょっと面白い、というか、ときによると紛らわしいかもしれません。

Javaの文字列関係のAPIはJDK 1.5 (Java 5)でサロゲートペア対応のために大きく変わりましたが、その後、Java 7でも地味にCharacterクラスにメソッドが追加されていたりします。

  • public static boolean isBmpCodePoint(int codePoint)
  • public static boolean isSurrogate(char ch)
  • public static char highSurrogate(int codePoint)
  • public static char lowSurrogate(int codePoint)
  • public static boolean isAlphabetic(int codePoint)
  • public static boolean isIdeographic(int codePoint)
  • public static int compare(char x, char y)
  • public static String getName(int codePoint)

大体メソッド名から推測できるものが多いです。

注意が必要な点として、isAlphabetic(int)は日本人が「アルファベット」と聞いて真っ先に思い浮かべるラテンアルファベットだけでなく、ギリシャやキリルも、それどころか平仮名や漢字さえ含んでいます。記号類でない言語表記のための文字が大体相当すると思っていいでしょう。定義はメソッドの説明に記されているので、用途に応じて便利なケースがあれば使えばよいでしょう。ちなみにカテゴリMnは含んでいないので、結合文字は(例えば合成用の濁点やアクセント記号等) falseになります。

isIdeographic(int)は漢字かどうかを判定します。一部の人がすぐに気にしたであろう互換漢字もこれでtrueを返します。「々」を与えるとfalseになります。

getName(int)は普通のアプリケーションでは使わないかもしれませんが、一部の人(?)は歓迎しそうです。Character.getName(0x3042) とすると "HIRAGANA LETTER A" が得られます。

メソッドでないのですが、Character.UnicodeScriptというクラスが新たに定義されています。これは Unicode Standard Annex #24: Script Names という文書に記されている属性定義を利用できるものです。

例えば、

Character.UnicodeScript s = Character.UnicodeScript.of(0x3042); // 「あ」

とすると、enum定数のHIRAGANAが得られます。

では平仮名と片仮名の両方で用いられる長音符号「ー」はどうなのかというと、これは上記の文書の定義に従って「COMMON」になります。ちなみに合成用の濁点(結合文字)はINHERITEDというものになります。前の文字に同じ、という意味のようです。

漢字は定数HANです。「々」もHANになります。

便利そうな感じはしますが、定義に気をつけて良く吟味しないと期待通りに使えないかもしれないので注意ですね。Unicode Character Databaseの一部として用意されているデータファイルから各文字の値が得られます。

UTF-8のCSVファイルを扱うプログラムが理由のわからないエラーを出したとき、原因が入力ファイルのBOMだったことがあります。

1行目の先頭にU+FEFFがついていて、ファイルを読み込む処理でそれを落とさなかったために、U+FEFFもデータの一部として扱われてしまったためです。つまり最初のレコードの最初のフィールドにゴミがついてしまったわけです。

この問題が厄介なのは、データの中身をテキストエディタやコンソールで見てもよくわからないことです。U+FEFFは "ZERO WIDTH NO-BREAK SPACE" であって目に見えない存在であるので、ソフトウェアがきちんと対応しているほど、存在が隠れてしまうわけです。いっそ豆腐にでもなってくれれば異常に気付きやすいのですが。

(余談ながら、ネットのジョークに「お前のコードに全角スペースを入れたぞ」「なにー」みたいなのがありますが、和字間隔(全角スペース)は可視化するエディタも多く、昔からよく知られているだけに対処も容易であって、U+FEFFやその他Unicodeの制御文字の類いの方がずっと面倒です)

ここで、もし、CSVファイルの1行目がヘッダ行であって、なおかつそのヘッダ行を(あるいは少なくともヘッダの先頭の項目を)単に読み飛ばすようになっていると、BOMがあろうがなかろうが同じことになります。

つまり、たいして必要でなくても(というかむしろ必要でない方が好都合)、ヘッダ行を設けておくと、BOMよけとして働いてくれるわけです。

もっとも、本当は、UTF-8のファイル先頭のBOM (バイト列 EF BB BF) をプログラムが読み飛ばすようになっている方がいいわけで、これはあまりちゃんとした対処ではありません。

参考:

新年早々、大笑いしてしまったこと。

下らないといえば下らないので書くまでもないかと思ったのですが、後で忘れた頃に読み返すと面白いかもしれないので書きとめておくことにします。

何があったのかは下記のページに詳しく書かれてあります。こちらを読んでいただければ、ぶっちゃけそれ以上のことはないです。

簡単にまとめていうと、

  • LINE上で「ウイルス」なるものを送りつけることができるという噂があって、実際にそれを送りつけられるとLINEのアプリが誤動作(重くなる)らしい
  • 実際のところ、ここで「ウイルス」と呼ばれているものはある特定の文字列である (プログラムではない。であるからしてウイルスでもない)
  • 特定の文字列を受け取ると動作が極端に重くなる不具合のあるアプリがある、というのが真相らしい
  • 問題を引き起こす文字列は、UnicodeのU+FFFD (replacement character)をたくさん並べたものだそうだ (see 「変な「はてなマーク�」でLINEやタイムラインが固まって動かなくなる不具合が発生中」)

問題のアプリでU+FFFDのたくさん並んだ文字列を受信すると重くなるというのは、なぜなのかはよく分かりません。アプリなりOSなりが直されるべき問題であるように思われます。

結局のところウイルスではなかったのですが、私が目を見張ったのはそのあと。

Unicodeがなんであるかを知らない普通の人たちの間で「ユニコード」という言葉が一人歩きして、あらぬ方向に向かってしまったようです。上記リンク先ページのこのくだりは衝撃的です。

「ユニコード」という単語が聞き慣れないせいか、この「ウイルス」のことはそのまま別名「ユニコード」と呼ばれており、「ウイルスはただのユニコードだろ」とか「ユニコードは犯罪だからやめてください」などと言われたりします。

「ユニコードは犯罪だからやめてください」。このフレーズの破壊力はすごい! 思わず大笑いしてしまいました。

ウェブ検索で「ユニコード 犯罪」といった語句で検索すると、Q&Aサイトや個人ブログなどがヒットしてなかなかすごい結果が出てきます。「ユニコードは犯罪になるのですか? ならないと言っている人もいるのですが」「ユニコード使うと電子計算機損壊等業務妨害という犯罪になるらしい」「「ユニコードを打ったら犯罪」 「3000万以下の罰金と、 懲役10年くらい」と言われました」。

ユニコードって本当は何なんでしょうか? それは、この本を読むと分かると思います。 :-)

結合文字についてMacのおしい点

Mac OS Xには標準でアイヌ語用の入力方式が搭載されています。アイヌ語のモードにした上で、例えば "sirpopke" とローマ字を打鍵すると「シㇼポㇷ゚ケ」となり、「ㇼ」や「ㇷ゚」といったアイヌ語表記用の片仮名を自然に入力することができます。これは市場性を考慮するとなかなかすごいことだと思います。

それはいいのですが、こうして入力できるにもかかわらず、一部の文字、Unicodeで結合文字を使わないと表現できない文字について、OS Xに標準添付のソフトウェアで適切に表示できないことがあります。

端的には、アイヌ語の片仮名表記に頻出する「ㇷ゚」が挙げられます。この文字はJIS X 0213では単独の符号位置(1面6区88点)が与えられていますが、Unicodeでは合成用の半濁点(U+309A)を「ㇷ」のあとに続けて、ふたつの符号位置を並べて表現する必要があります。

例えば、このページをOS Xに添付のSafariで見ると、「ㇷ゚」の濁点のところに妙に間が空いてしまうと思います。しかし、この文字列をマウスでコピーして、やはりOS添付のテキストエディタであるテキストエディットに貼り付けると、きちんと一文字として表示されるはずです。Firefoxでは一文字の幅に表示されますが、編集用のテキストエリアでは表示が若干崩れるようです(今まさにMac上のFirefoxで編集しています)。

フォントのせいなのか文字表示のライブラリのせいなのかよくわかりませんが、ユーザの視点からすると、まだちょっと惜しいという感じです。

同種の文字としては「ト゚」などがありますが、今日での使用頻度はあまり高くないと思います。

ちなみに「ㇷ゚」については朝鮮語(韓国語)音を片仮名で記すのに利用する人もいるようです。

【2013年10月26日追記】この記事を公開した直後なのですが、新たに配布されたOS X MavericksについてくるSafariでは、上記の問題は起こらないようです。ただし、MacでなくiPadのSafariでは、iOSの最新版7.0.3でも上記と同じ問題があります。

2 3 4  

最近のブログ記事

仮名合字・合略仮名の文字コード
合字とは 合字というものがあります。複数…
なぜ『プログラマのための文字コード技術入門』の改訂新版にはSKKと Emacsの話が入っていないのか
拙著『[改訂新版] プログラマのための文…
朝鮮半島の訃報の第3水準漢字
朝鮮戦争で韓国軍として活躍した白善燁氏が…
テレワークの環境改善〜CO2濃度をチェックする
テレワークの問題点 新型コロナウイルスの…
エンジニアHubにて「文字コード再入門─ Unicodeでのサロゲートペア、結合文字、正規化、書記素クラスタを理解しよう!」公開
「エンジニアHub」にて記事を執筆しまし…

広告