Help us understand the problem. What is going on with this article?

Unicodeで半角全角を扱う Ambiguous(曖昧さ)とUncertainty(不確実性)の恐怖

はじめに

この記事はこちらで発表した内容を、読み物としてまとめなおしたものです。こちらに動画も公開していますので、よかったら合わせてご覧ください。

さて、みなさんも「コンソールで全角半角を適切に扱って表示したい」なんて考えたことが、一度はあるのではないでしょうか?

かくいう私は、ツール作成やAPIのお試しのときに、コンソールにテーブル状に結果表示したいと思うことが何度かありました。そのためFluentTextTableというコンソールに表を出力するテキストテーブルライブラリを自作し、その中でUnicodeも文字列の全角・半角判定を実装したのですが・・・そこで遭遇してしまいました。

「Unicodeで半角全角を扱う Ambiguous(曖昧さ)とUncertainty(不確実性)の恐怖」

に。

結論から言いますと、Unicodeで半角全角を完璧に扱い分けることは不可能です。

今回はこのあたりの闇についてお伝えしたいと思います。

Unicodeにおける半角全角判定

まずは基本から。Unicodeには、各種文字種別を扱うための複数の辞書が規定されています。

半角全角を規定した辞書も存在していて、それが「UAX #11: East Asian Width」で、実際の辞書はこちらに公開されています。

中を覗いてみると、つぎのように記述されているのが見て取れます。

image.png

半角全角を判定する上で必要なのは、#より左の「;」で区切られた2つの領域です。

「;」の左側は文字コードの範囲を表していて、例えば「0000..001F」であれば「0x0000~0x001F」の範囲を表しますし、「0020」であれば単独の「0x0020」の文字を表します。

「;」の右側は文字の種別で、East Asian Widthでは6種類規定されています。それぞれの種別は東アジア圏の文章か、それ以外で記述されたかどうかによって振る舞いが変わります。

具体的には以下の通りです。

種別 東アジア それ以外
Ambiguous 全角 半角(正確にはnarrow)
Fullwidth 全角 未使用
Halfwidth 半角 未使用
Narrow 半角 半角(正確にはnarrow)
Wide 全角 未使用
Neutral 半角 半角(正確にはnarrow)

Ambiguousだけ東アジアか否かによって扱いを変える必要があります。

FullwidthとWideは東アジア圏では全角で扱いますが、それ以外の文化圏の文章には登場しないため考慮する必要がありません。

東アジア圏かどうか?をどう判定するべきかはプラットフォームによって異なります。私は.NETで扱ったのでデフォルトはCurrentUICultureInfoで処理分岐するようにしました。

さて、ここまでが基本です。

ここから先が闇です。

闇の始まり

さて、先ほどの扱いについては、UAX #11: East Asian Widthに明確に記載されています。

しかし、実際に文字をひとつずつ追いかけていくと怪しい文字が頻出します。

ここからは日本で最も著名な等幅フォントである「MS ゴシック」で見ていきたいと思います。

さてAmbiguousは全角で扱います。Ambiguousには「☎」や「®」が含まれます。これをWindowsのメモ帳で見てみましょう。

image.png

は?私は初めて見た時、辞書を読み間違えたのかと思いました。

しかし「®」は0x00aeで、確かにAmbiguousと規定されています。

image.png

これを皮切りに、出るわ出るわ。怪しい文字が・・・

image.png

どちらもNeturalで半角表示のはずです。「©」はちゃんと表示されていますが「⏭」はなぜか全角です。

また「⏭」に似てるのに、なぜかWideな「⏩」ですが、同じWideの「⌛」はここに極まれりという感じで・・・

image.png

は?0.75角?でもこれ実はよくよく見ると⏭も⏩も実はおかしくて・・・

image.png

ずれとる・・1.03125角・・・・。

バグも

Linuxのコンソールでは半角全角の扱いは難しいようですが、まともだと思っていたWindowsのコマンドプロンプトでもバグを踏んでしまいました。

先にも書いたように、私は今回コンソール出力するためのテキストテーブルライブラリを作成していました。

日本人ならテキストでテーブル記述するなら罫線文字「┌─┬┐」を使いたいですよね?FluentTextTableでは罫線をカスタマイズ可能にしていたので、罫線文字をつかうプリセットを用意してみました。

image.png

出力しました。

image.png

はぁ?これを選択して、メモ帳様にコピペすると・・・

image.png

ちゃんと表示されます。なぜだ・・・なぜなんだ・・・。はっもしかして!?

image.png

image.png

バグか・・・

いやでもコマンドプロンプトはWindowsでももうオワコン。これからの時代はクロスプラットフォーム化されたWindows Terminal様の出番のはずだ!

image.png

貫通はしない。貫通はしないが半角!ずれるじゃん!

まとめ

という訳で、Unicodeで半角全角を扱う場合、まずフォントがEast Asian Widthの規定を正しく守っている必要があります。でも実際にはそうとは限りません。

またそれを取り扱うプラットフォームも適切に実装されている必要がありますが、必ずしもそうとは限りません。

まぁ後者はOSSであれば修正に協力することも可能でしょうが、前者は・・・

Unicode時代に半角全角を扱う際は、ある程度は「諦め」が必要です。

というわけで

「Unicodeで半角全角を扱う Ambiguous(曖昧さ)とUncertainty(不確実性)の恐怖」

の片りんを味わっていただけたでしょうか?

今回はここまで。それではまた!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした