『○○文字以内』と気軽に言う前に

229 views

Published on

Unicode時代の「文字数」の考え方について。

Published in: Engineering
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
229
On SlideShare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

『○○文字以内』と気軽に言う前に

  1. 1. 『○○文字以内』と気軽に言う前に Unicodeの闇をのぞき込む心構え 株式会社インターコム 開発部勉強会2016-07-22 CS開発G 三浦琢磨
  2. 2. 文字数ってなんでしたっけ
  3. 3. 文字数ってなんでしたっけ  データベース設計「full_nameカラムは最大64文字にします」  アプリケーション「じゃあ64文字より長い文字列入力にはエラー返します」  氏名入力フォーム「氏名は最大64文字ですと注意書きしておきます」 このシステムは意図したとおりに動くでしょうか。 ↓ 各モジュールが想定する「文字数」の単位が一致していないと、思わぬ意図しない動作が起こります。
  4. 4. 文字数ってなんでしたっけ 文字数を扱うソフトウェア仕様は混乱しがちです。 その理由を「文字数」の歴史をたどりながら説明します。 ※歴史=日本のパソコンユーザー視点の偏った歴史
  5. 5. 文字数ってなんでしたっけ 文字数の歴史 1.非常に素朴だった時代(1970年代=ANK文字) 人間の数える文字 文字コードの並び バイト数 ABC123モジスウ || 1対1対応 || 1対1対応 11文字ある! 11個ある! 11バイトある!
  6. 6. 文字数ってなんでしたっけ 文字数の歴史 2.まだまだ素朴だった時代(1980~90年代=シフトJIS) 人間の数える文字 文字コードの並び バイト数 ABC日本語モジスウ || 1対1対応 ↓ 1バイトと2バイトが混在 11文字ある! 11個ある! 14バイトある! || 1対1対応 表示幅 14桁ある! バイト数を数えればそ のまま表示幅だったの で、文字数でなく表示 幅をテキストサイズと して扱うことが多かっ た。 「半角50文字まで」 「1byte/2byte文字」 「全角/半角文字」 「半角カナ」
  7. 7. 文字数ってなんでしたっけ 文字数の歴史 3.再び、非常に素朴になった はずだった(幻の世界=Unicode1.1) 人間の数える文字 文字コードの並び バイト数(ワード数) 日本語ABC한글 || 1対1対応 || 2バイト(1ワード) 8文字ある! 8個ある! 16バイト(8ワード)ある! なぜ「はずだった」 まぼろしの世界を紹 介するか⋯ それは、いまだに Unicodeがこのように 素朴であると広く信 じられているから。
  8. 8. 文字数ってなんでしたっけ 文字数の歴史 4.現実にやってきた地獄の時代(2000年代以降=Unicode) 人間の数える文字 文字コードの並び バイト数 ↓ 1文字あたり1コード以上 UTF-16 2バイト(少数が4バイト) 3文字ある! 4個ある・・・ 10バイト(5ワード)あ る!? バイト数 UTF-8 1,2,3,4バイトが混在 13バイトある 表示幅はもちろん プロポーショナル だから全角も半角 もない
  9. 9. 地獄のUnicode
  10. 10. 地獄のUnicode  人間にとっての1文字が複数の文字コード(コードポイント)並びで表現される 例: 1.結合文字 「が」←「が」一文字で表現もできるし「か」「゛」の並びでも表現できる。 一文字が正規とする正規化方法と二文字が正規とする正規化方法、両方ある。 2.異体字セレクタ 「塚」←「塚」「異体字E0101」の並びで表現。ただしコードポイント一つで表現する「互換漢字」 という表現も非正規で存在。
  11. 11. 地獄のUnicode  一つのコードポイントが2バイトと限らない UTF-16 ほとんどの文字は2バイト。 (Unicode1.1時代のエンコーディングに上位互換) 複雑な漢字や絵文字や異体字セレクタが4バイト。 UTF-8 ASCII文字は1バイト。(ASCIIに上位互換する) 欧文文字・アラビア文字が大体2バイト。 欧文文字・アラビア文字以外の大体は3バイト。 複雑な漢字や絵文字や異体字セレクタが4バイト。 通信やデータ交換の世界ではUTF-8が主流。 エンコーディングが不明でもとりあえず ASCIIで読み始めてもらえば文書内に「こ れはUTF-8です」と書いておけるので (XMLが採用している方式)。 アプリの内部コードは、 Windows,Java,C#ではUTF-16。 (char型が1個で2バイトを格納する)
  12. 12. 地獄のUnicode 「いったい、何を基準にテキストサイズを数えて、 マニュアルには基準をどう説明すればいいんですか」
  13. 13. 地獄で生きていく
  14. 14. 地獄で生きていく  テキストサイズを数える基準は4通りしかありません。  人間の目に見える文字数  コードポイント数  UTF-16でのバイト数(ワード数)  UTF-8でのバイト数 ここからどれかを選ぶしかありません。
  15. 15. 地獄で生きていく  ここで、プログラムでの各種テキストサイズの求め方  Java(文字列の内部表現はUTF-16) UTF-16でのワード数 ・・・ str.length UTF-8でのバイト数 ・・・ str.getBytes("UTF-8").length コードポイント数 ・・・ str.codePointCount() 人間の見る文字数 ・・・ BreakIterator.getCharacterInstance() を使って数える  C#(文字列の内部表現はUTF-16) UTF-16でのワード数 ・・・ str.Length UTF-8でのバイト数 ・・・ Encoding.UTF8.GetByteCount(str) コードポイント数 ・・・ new StringInfo(str).LengthInTextElements 人間の見る文字数 ・・・ StringInfo.GetTextElementEnumerator(str) を使って数える
  16. 16. 地獄で生きていく  プログラム以外での文字数制限  HTML INPUT要素のmaxlength =UTF-16でのワード数  データベースのvarchar =DB製品ごとに基準が異なる 特に、UTF-8とUTF-16をごっちゃにした謎のエンコーディングを基準にする製品がある(Oracle)
  17. 17. 地獄で生きていく アプリでは各種基準で文字数制限をプログラミングできるが、 フロントエンドもバックエンドもまったく自分勝手。 =地獄
  18. 18. 地獄で生きていく こうして生きていこう!!!  DBの文字列カラムには、長さを設定しない (最近のDBは長さ制限なしで問題ないパフォーマンスが出ます)  HTML INPUTのmaxlengthは使える(正規化をサーバと合わせられるなら)  長さ制限の基準はUTF-16でのワード数(バイト数÷2)とする その理由:  フロントエンド(JavaScript)でも str.length で求められる。  なんだかんだいって大体実際の文字数と同じくらい  通信がUTF-8だとしても、UTF-8バイト数はUTF-16バイト数の最大1.5倍なので最大通信量は予測可能
  19. 19. 地獄で生きていく こうして生きていこう!!!  数える前にNFC正規化をかけるとより良い。フロントエンドでもES6から可能に。 (NFC正規化=「か」「゛」→「が」)  マニュアルや入力ガイドにはこう書いてしまう  「約50文字まで入力できます」  「残り約5文字」  「残り入力可能:10%」(長いテキストボックスの場合) 異体字を入力すると残り文字数がいきなり3文字減るけど「約」だからいいんです。
  20. 20. まとめ  結局のところ、文字数制限はもっとも安易なUTF-16ワード数(str.length)でかけるが一番現 実的な対応になります。  来るはずだった幻の素朴な世界での数え方なのですが、現実とのずれは魔法の言葉「約」でお茶 を濁します。  「約」で逃げられるのはテキストサイズ制限という分野に限っての話! テキストを扱うときは常に「人間に見える文字」「コードポイント」「バイト(ワード)」の3段 階のどれを相手にしているのかを常に意識してください。

×