Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
エンジニアが知っておくべき文字コード問題のあれこれ
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Yasuyuki Higa
May 25, 2024
Programming
380
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
エンジニアが知っておくべき文字コード問題のあれこれ
Yasuyuki Higa
May 25, 2024
More Decks by Yasuyuki Higa
See All by Yasuyuki Higa
AI as a Tester
yasuyuki_higa
0
93
ふつうのWebアプリケーションとキャッシュ
yasuyuki_higa
1
210
Other Decks in Programming
See All in Programming
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
180
才能?センス?知らん、 続けたもん勝ちだ。-- 結婚・出産・癌を越えてなお、私がプロダクトを創り続ける理由
16bitidol
1
260
Inside Stream API
skrb
1
770
TAKTでAI駆動開発の品質を設計する
j5ik2o
7
1.5k
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
4.5k
Oxlintのカスタムルールの現況
syumai
6
1.1k
AIで効率化できた業務・日常
ochtum
0
140
Datadog × OpenTelemetry 入門と実践のあいだ
kn_to_maxpno
1
180
AI 輔助遺留系統現代化的經驗分享
jame2408
1
980
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
800
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
150
「なぜそう決めたのか」を残し続ける仕組み ― Notion AI カスタムエージェント × Slack連携による設計判断の自動記録 - NIKKEI Tech Talk #47
niftycorp
PRO
0
230
Featured
See All Featured
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
240
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
210
エンジニアに許された特別な時間の終わり
watany
107
250k
How to build a perfect <img>
jonoalderson
1
5.7k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
Mind Mapping
helmedeiros
PRO
1
260
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
330
sira's awesome portfolio website redesign presentation
elsirapls
0
280
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.4k
The Limits of Empathy - UXLibs8
cassininazir
1
370
Transcript
エンジニアが知っておくべき文字コード 問題のあれこれ Laravel 勉強会 in 奈良 Yasuyuki Higa @yh65743
自己紹介 名前: 比嘉 康至(ひが やすゆき) X(旧Twitter): @yh65743 勤務先: 株式会社ことば研究所 居住地:
奈良(フルリモートで勤務しています) ❏ PHP ❏ React ❏ TypeScript 普段はこのあたりを使ってWebアプリケーション開発/保守 やってます
文字コードってよくわかんなくないですか? • ASCII や Unicode の概念は何となくわかるけど。。。 • 「あ」(U+3042) を UTF-8
のコード値にすると e3 81 82 ◦ -> なんで? Unicode のコードポイントがそのままコード値になるんじゃないの ? • 「Windows ではバックスラッシュが円記号になります」 -> あれなんでなん? • MySQL の Character set を utf8 から utf8mb4 にしないと寿司がビールになります ◦ -> ??????? • こういうのをちゃんと理解したい
矢野 啓介 『プログラマのための文字コード技術入門 』 技術評論社 (2018/12/22) 本日の発表はだいたいこの本からの引用となっており ます
円記号問題 • 「Windows ではバックスラッシュ(\) が円記号(¥) になる」という有名な話 • Shift-JIS エンコーディングのシステム上で入力された円記号が他のエンコーディン グのシステム上ではバックスラッシュに見える(逆も然り)という現象のこと
• 記号の表示が変わるだけの問題に思えるが……?
そもそも文字コードとは • コンピューターはデータを0と1(ビット)の羅列で扱う -> そのままでは「文字」を扱え ない • 文字を扱うにはビット列と文字の対応表が必要 A =
001 B = 010 C = 011 … • この文字とビット列の対応表を文字コードという
ASCII • American Standard Code for Information Interchange • 1960年代制定の規格
• 7ビット = 2^7 = 128 種類の文字を表現 • 0x00 から 0x1F までの位置は制御文字 • 英語を表現するだけならこれで十分 上位3ビット 下 位 4 ビ ッ ト 制御文字
ISO/IEC 646 • ASCII では英語圏以外困ることになるので ASCII をベースに した国際規格が作られた。それが ISO/IEC 646
• ★の部分は各国の都合で変えて良い • # と £(ポンド)、¤(国際通貨記号)と $ はどちらかを選択する 必要がある 上位3ビット 下 位 4 ビ ッ ト 制御文字
JIS X 0201 • ISO/IEC 646 の日本版規格 • ASCII とほぼ同じコード表だが2箇所だけ違う
◦ 0x5C が ASCII では \ (バックスラッシュ) JIS X 0201 では ¥(円記号) ◦ 0x7E が ASCII では ~(チルダ) JIS X 0201 では ¯(オーバーライン) → そもそもの円記号問題の始まり。 とはいえこれはあくまで規格に則った動作なのだが。。。 • C言語のエスケープシーケンスで \ が使われるように • さらに MS-DOS がパス区切り文字として \ を使ってしまう • なんで国によって変わるような文字を使っちゃうの。。。
ISO/IEC 2022 • ISO/IEC 646 の各国版だけだと複数の言語を混在させられな い • そこで複数の文字コードを同時に使える規格として ISO/IEC
2022 が考案された • 第8ビットを導入し、ISO/IEC 646 準拠の文字コードを混在で きる(第8ビットが0なら ASCII, 1なら JIS X 0201 みたいにでき る) • エスケープ(0x1B) を使うことで文字コードの切り替えもできる • さらに漢字など 7ビットで収まりきらない文字のために複数バ イトで文字を表現できるようになった 第8ビットが0 第8ビットが1
JIS X 0208 • ISO/IEC 2022 に準拠した日本の2バイトコード規格 • いわゆる「JIS 第1・第2水準漢字」を定めているのがこれ
• ASCII の制御文字以外の部分94箇所を1バイト目、2バイト目に使用し、 94*94 = 8,836 文字 収録可能 • ASCII と同じアルファベットや数字を含んでいるが、2バイトコードであり ASCII や JIS X 0201 と互換性はない -> Shift_JIS や EUC-JP といった 1バイトコードと と JIS X 0208 を併用するための文字符号化方式が生まれる
EUC-JP と Shift_JIS • どちらも1バイトコード と JIS X 0208 を併用するための文字符号化方式
• EUC-JP は UNIX系OSで、Shift_JIS は MS-DOS のWindows で使われた • EUC-JP は 1バイトコードとして ASCII を、Shift_JIS は JIS X 0201 を使用 ◦ どちらも1バイトコード部分は互換性があるので ASCII/JIS X 0201 の文字コー ドはそのまま使える -> EUC-JP ⇔ Shift_JIS 間で文字コード変換したら1バイト 部分は変換されずにそのままになってる ◦ 大部分はそれで問題ないけど ASCII と JIS X 0201 で同じコードで違う記号に なっている \ と ¥ が文字化けすることに
Unicode で円記号が問題になる理由 • 世界中の文字を1つの文字コードで表現するために考案されたのが Unicode • Unicode は先頭の128符号位置が ASCII と一致するようになっており、次の
128符 号位置は ISO/IEC 8859-1 というヨーロッパの文字コードと一致するように作られて いる。そして ISO/IEC 8859-1 には バックスラッシュとは別に円記号の符号位置が 定められている(U+00A5)。 • Shift-JIS -> Unicode に変換したときに 0x5C は U+00A5 の円記号に変換されるこ とに。バックスラッシュとしての特別な意味が失われてしまう。 • 逆に Unicode の円記号を Shift-JIS に変換したとき勝手にエスケープシーケンスに なってしまう。
円記号問題の対処法 • 「全角」の円記号(JIS X 0201 ではなくJIS X 0208 の円記号)を使うようにする ◦
Unicode から Shift_JIS に変換したときに勝手にエスケープシーケンスとして扱われることを避けら れる ◦ PHP では 8.1.8 から mb_convert_encoding で UTF-8 の円記号を Shift_JIS に変換すると全角円 記号(818F)に変換されるようになったようです • とはいえ Shift_JIS の半角円記号がどっちの意味で使われてるか機械的に判別す ることは困難なので、どう扱うかは事前に決めておく必要がある。
寿司ビール問題 • MySQL で CHARACTER SET が utf8 になっていると 4バイト文字が扱えない
◦ utf8mb4 を指定することで 4バイト文字が格納できるようになる • また、Collation(照合順序)が utf8mb4_general_ci だと絵文字の区別ができず、 where句で値が 🍣 のレコードを指定したのに 🍺 のレコードもヒットしてしまった、 みたいな現象が起こる。これが寿司ビール問題 • そもそも UTF-8 と Unicode の関係って何? 何で3バイトの文字と4バイトの文字が あるの? (1バイト文字、2バイト文字もあります)みたいなところがわからないとこの 問題の理解がふわっとしてしまう
Unicode の歴史 • 当初、全世界の文字を収めた文字コードの規格として ISO/IEC 10646 が考案され ていた。 • 当初
ISO/IEC 10646 は4バイトで1文字を表す予定だった。 • ところが同時期にコンピューター関連企業が同様の目的を持った規格を開発し始 めた。この規格が Unicode • 同じ目的の国際文字コードが並立するのは好ましくないので2つの規格を統合する ことに。 • ところが Unicode は2バイトコードだった。そこで4バイトの下位2バイトだけを使用し 上位2バイトは0000で埋めるだけに。 ◦ -> つまり当初 Unicode は実質2バイトコードだった
Unicode の歴史 • 事実上2バイトコードとして制定された Unicode だったが世界中の文字を収録する には2バイトでは足りないことが明らかに。 • この始まりの2バイトコードの範囲を基本多言語面(Basic Multilingual
Plan 略して BMP)と呼び、ここには普段よく使われている文字が収録されている • もともと2バイト=16ビット固定長の文字コードだった Unicode で BMP 以外の範囲 を扱う方法として UTF-16 という文字符号化方式が考案された
符号化文字集合と文字符号化方式 符号化文字集合: 文字と数値の対応表のこと 文字符号化方式: 符号化文字集合によって割り出された文字に対応する数値をコン ピュータシステムが利用できるバイト列に変換する方式のこと ASCII/JIS X 0201, JIS
X 0208, Unicode : 符号化文字集合 EUC-JP, Shift_JIS, UTF-16, UTF-8 : 文字符号化方式 複数の符号化文字集合を組み合わせたする場合は単に文字のコード値を並べるだけで は無理 -> 文字符号化方式が必要、ということ
UTF-16 • 本来の Unicode が意図していた符号化方式 • BMP の文字は2バイト(16ビット)で符号をそのまま並べ、BMP以外の文字に関し てはサロゲートペアと呼ばれる特殊な計算で求めたビット列を4バイト並べて表現す る
• 全て4バイト固定長で表現する UTF-32 という符号化方式もある
UTF-8 • 1文字を1バイトから4バイトまでの可変長で符号化する方式。 • 以下の表に基づいて符号位置のビット列を x にあてはめる Unicodeの符号位置 UTF-8のバイト列 00000000
~ 0000007F 0xxxxxxx 00000000 ~ 000007FF 110xxxxx 10xxxxxx 00000800 ~ 0000FFFF 1110xxxx 10xxxxxx 10xxxxxx 00010000 ~ 0010FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
UTF-8 • 試しに「あ」を符号化してみる ◦ Unicode で 「あ」は U+3042 -> 二進数で
00110000 01000010 ◦ 3042 は表で3行目にあたるので 1110xxxx 10xxxxxx 10xxxxxx に上記ビットをあてはめる ◦ すると 11100011 10000001 10000010 -> 16進数にすると E3 81 82 これが 「あ」の UTF-8によって エンコードされた値 • 表の1行目は ASCII まんまなので互換性がある • 表の3行目までは BMP の範囲内 -> 「3バイトのUTF-8」はよく使われる基礎的な文 字なので多くのソフトウェアで実装されているが、4バイト文字に関してはそうではな いということ
波ダッシュ問題 • JIS X 0208 の 〜(波ダッシュ)が Unicode に変換された際に U+301C(WAVE
DASH)に なったり U+FF5E (FULLWIDTH TILDE)になったりする問題のこと。
波ダッシュ問題 • ある Shift_JIS のシステム上で作られた波ダッシュを含むデータを Unicode に変換 するとする。 • 変換したデータを別の
Shift_JIS 実装で動いているシステムで使うために再度文字 コードを変換したとき、最初のシステムが波ダッシュを U+301 に紐づける実装で、 もう一つのシステムが波ダッシュを U+FF5E に紐づける実装だと再変換で文字化 けする可能性がある。
波ダッシュ問題の原因 • JIS X 0208 の 「〜」(1区33点)と Unicode の「〜」(U+301C)は共に “WAVE
DASH” という文字名が与えられており Unicode への変換において妥当なのは U+301C への変換だと思われる • しかし Unicode は以前 WAVE DASH の例示字形として右肩上がりの波線を提示し ており、そのせいで誤解を生むことになってしまった。 普通の波ダッシュ Unicode の例示字形
波ダッシュ問題の対処法 • 変換方法を揃えるか、Unicode に変換後 文字自体をU+301C か U+FF5E のどちら かに強制的に変換して揃えてしまう。 •
波ダッシュ以外にも、ǁ, −, ¢, £, ¬ のような記号で同様の問題が起こり得るので注 意が必要