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
nkfのソースコードリーディングをした話 - Kashiwa.rb #2 LT
Search
Koji NAKAMURA
August 26, 2024
Technology
250
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
nkfのソースコードリーディングをした話 - Kashiwa.rb #2 LT
Koji NAKAMURA
August 26, 2024
More Decks by Koji NAKAMURA
See All by Koji NAKAMURA
Lightning近況報告
kozy4324
0
250
龍昌餃子で理解するWebサーバーの並行処理モデル - 東葛.dev #9
kozy4324
1
310
Rubyで作る論理回路シミュレータの設計の話 - Kashiwa.rb #12
kozy4324
1
600
Rubyで作る論理回路シミュレータ - Shinjuku.rb #99
kozy4324
0
120
Steep導入したいRTA - Kashiwa.rb #11
kozy4324
0
220
これまで細々と作成したGemの紹介をします - Kashiwa.rb #9
kozy4324
0
300
東京Ruby会議12のお手伝いしてきた話
kozy4324
0
140
個人開発発表 LT - Shinjuku.rb #97
kozy4324
0
560
Ruby界隈を中心に2024をふりかえる - Kashiwa.rb #6
kozy4324
0
240
Other Decks in Technology
See All in Technology
オブザーバビリティ、本当に活用できてる? 〜API連携×生成AIで成熟度を自動評価〜
dmmsre
1
3k
Zoom2Youtube.Claude
kawaguti
PRO
3
490
ADDF - ループエンジニアリングするフレームワークを作ったら/I Didn't Set Out to Build Loop Engineering, But ADDF Did
fruitriin
0
120
型は壁、Rustでもバグを直すな、表現できなくせよ
nwiizo
13
2k
ヘルスケア領域における AI 活用と その安全性担保のための取り組み (Leveraging AI in Healthcare and Our Efforts to Ensure Its Safety) - Google I/O Extended Tokyo 2026, July 11, 2026
zettaittenani
0
270
CIで使うClaude
iwatatomoya
0
240
SRE Lounge Hiroshimaへの招待
grimoh
0
640
インフラと開発の垣根を超えていき!〜元AWSインフラエンジニアがAWS開発で奮闘している話〜
hatahata021
1
160
生成AIの活用/high_school2026
okana2ki
0
130
Amazon EVS で VCF 9.0 / 9.1 のサポート開始まとめ
mtoyoda
0
290
AI Driven AI Governance
pict3
0
330
「早く出す」より「事業に効く」 ── 顧客の業務サイクルから逆算するAI時代の二重ループ開発と「変化の設計者」 / devsumi2026
rakus_dev
1
220
Featured
See All Featured
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.6k
How to build a perfect <img>
jonoalderson
1
5.8k
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.1k
Building Applications with DynamoDB
mza
96
7.1k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.4k
The Cost Of JavaScript in 2023
addyosmani
55
10k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
420
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Designing Experiences People Love
moore
143
24k
Code Reviewing Like a Champion
maltzj
528
40k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Transcript
nkfのソースコード リーディングをした話 〜そのために必要な最低限の文字コード入門〜 2024.08.26 Kashiwa.rb #2 LT Koji NAKAMURA (@kozy4324)
kozy4324 = { name: "Koji NAKAMURA", alias_name: "こーじ", 𝕏: "@kozy4324",
belongs_to: [ "Classi株式会社", "Shinjuku.rb", "Kashiwa.rb", ], } 自己紹介
あらすじ
バグ? or Notバグ?
None
その前に nkf とは • Ruby 標準添付ライブラリの一つ ◦ https://docs.ruby-lang.org/ja/latest/class/NKF.html • ネットワーク用漢字コード変換フィルタ
◦ ものすごく古くからある(初版は 1987年) ◦ 実装はC言語 • それを Ruby から使うためのモジュールが nkf gem • 機能は文字コード変換と文字コード推測 ◦ 冒頭の「シュールな振る舞い」と書いたのは文字コード推測の #guess メソッド
nkf のソースコードリーディングをしてみる (1) • /ext/nkf/nkf-utf8/nkf.c にある kanji_convert 関数から見ていくと良さそう ◦ https://github.com/ruby/nkf/blob/24e6ae66395a14d3022e1dd1210d04168e2c8d9e/ext/nkf/nkf-
utf8/nkf.c#L5847 • 文字のバイト列先頭から1バイト読むごとに code_status 関数で e_status, s_status, w_status を呼び出して何かを評価している ◦ https://github.com/ruby/nkf/blob/24e6ae66395a14d3022e1dd1210d04168e2c8d9e/ext/nkf/nkf- utf8/nkf.c#L3273 • それぞれが特定の文字コードらしいかどうかを評価しているみたい ◦ e_status => EUC-JP ◦ s_status => Shift_JIS ◦ w_status => UTF-8
そもそも nkf の文字コード判定ロジックどうなっている? • AI に聞いた ◦ バイトパターンの検査 ◦ 頻度解析
◦ 例外処理とファイルヘッダの利用 ◦ その他の補助的な判断
nkfのソースコードリーディングをしてみる (2) • 特定の文字コードらしいかどうかをスコア化して比較する ◦ スコアを足し込みする関数が code_score ◦ https://github.com/ruby/nkf/blob/24e6ae66395a14d3022e1dd1210d04168e2c8d9e/ext/nkf/nkf- utf8/nkf.c#L3019-L3049
◦ 足し込みされる値は定数化されている ◦ https://github.com/ruby/nkf/blob/24e6ae66395a14d3022e1dd1210d04168e2c8d9e/ext/nkf/nkf- utf8/nkf.c#L2956-L2964 • スコアが大きくなるほど、その文字コードではない、と判定される ◦ 無効なコードポイントが出てくると SCORE_NO_EXIST ◦ バイト列全体としておかしい場合は SCORE_ERROR • 1番スコアの低い {e,s,w}_status のものが推定された文字コードとなる
nkfのソースコードリーディングをしてみる (3) • 「ゔ」「あ」それぞれのUTF-8バイト列 ◦ ゔ => e38294(3バイト) ◦ あ
=> e38182(3バイト) • 「ゔ」「ゔああ」 ◦ Shift_JIS: SCORE_ERROR が設定される ◦ UTF-8: 「ゔ」で SCORE_NO_EXIST が設定される? ◦ 結果として UTF-8 と判定される • 「ゔあ」「ゔあああ」 ◦ Shift_JIS: 文字化けはする(「繧斐 ≠縺ゅ≠」)が Shift_JIS のバイト列として有効 ◦ UTF-8: 「ゔ」で SCORE_NO_EXIST が設定される? ◦ 結果として Shift_JIS と判定される、なるほど??
nkfのソースコードリーディングをしてみる (4) • SCORE_NO_EXIST が設定される w_status を読み進めてみた ◦ https://github.com/ruby/nkf/blob/24e6ae66395a14d3022e1dd1210d04168e2c8d9e/ext/nkf/nkf- utf8/nkf.c#L3215
◦ w2e_conv 関数を呼び出している ◦ https://github.com/ruby/nkf/blob/24e6ae66395a14d3022e1dd1210d04168e2c8d9e/ext/nkf/nkf- utf8/nkf.c#L3246-L3250 ◦ w(UTF-8) to e(EUC-JP) に変換している??? ◦ さらに w2e_conv では unicode_to_jis_common 関数を呼び出している ◦ https://github.com/ruby/nkf/blob/24e6ae66395a14d3022e1dd1210d04168e2c8d9e/ext/nkf/nkf- utf8/nkf.c#L2073 ◦ JIS???? ◦ EUC-JP どこいった?????
文字コード何もわからん \(^o^)/
作戦変更: まず文字コードについて基本を理解しよう
符号化文字集合 • ASCII ◦ 128の符号位置があって 7bit で表せる • JIS X
0201 ◦ ラテン文字集合(ASCIIと2文字違う)と片仮名の 1バイト文字集合 • JIS X 0208 ◦ 日本で使われる漢字・平仮名・片仮名等を収録した 2バイト文字集合 ◦ 漢字は第1水準と第2水準の物が含まれる • JIS X 0212 ◦ 補助漢字、JIS X 0208 と組み合わせて用いる • JIS X 0213 ◦ JIS X 0208 に足りない文字を補完するために開発された • Unicode ◦ 世界中の文字を収めることを目標にした符号化文字集合
符号化方式 • EUC-JP ◦ ASCII と JIS X 0208 を同時に用いる
8ビットの符号化方式 ◦ ASCII は 1バイト、JIS X 0208 は 2バイトで表現される ◦ 制御文字 SS2 と SS3 を使って JIS X 0201 片仮名集合と JIS X 0212 も扱える • Shift_JIS ◦ JIS X 0201 に JIS X 0208 を変形のうえ押し込んだもの ◦ JIS X 0201 は 1バイト、JIS X 0208 は 2バイトで表現される • UTF-8 ◦ Unicode の符号化方式、1文字で 1バイト〜 4バイトまでの長さをとり得る ◦ 符号位置とバイト列の対応 ▪ 00000000 〜 0000007F => 0xxxxxxx ▪ 00000080 〜 000007FF => 110xxxxx 10xxxxxx ▪ 00000800 〜 0000FFFF => 1110xxxx 10xxxxxx 10xxxxxx ▪ 00010000 〜 0010FFFF => 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
• https://ja.wikipedia.org/wiki/JIS_X_0213 ◦ > 平仮名 - 半濁点付きのか行(鼻濁音)、「ヴ」「ヵ」「ヶ」に対応する平仮名 つまり「ゔ」は JIS X
0208 (EUC-JP) には含まれていない文字! JIS X 0213 で追加された文字の概略
nkfのソースコードリーディングをしてみる (リベンジ) • w2e_conv => unicode_to_jis_common という流れ ◦ EUC-JP は
JIS X 0208 を単純に含むもの ◦ なので JIS (= JIS X 0208) への変換という解釈ができた • UTF-8 から EUC-JP への変換は変換テーブルを使う ◦ utf8_to_euc_E382 に行き着いた ◦ https://github.com/ruby/nkf/blob/24e6ae66395a14d3022e1dd1210d04168e2c8d9e/ext/nkf/nkf- utf8/utf8tbl.c#L4370-L4379 ◦ たしかに「ヴ」「ヵ」「ヶ」に対応する平仮名箇所のテーブルが歯抜けになっている ◦ SCORE_NO_EXIST となる機序は確認できた
まとめ
まとめ • nkf の文字コード推測において、UTF-8 の入力に JIS X 0213 の文字(というか EUC-JP
にない文字)が含まれると期待する結果は得られない ◦ UTF-8 かどうかの判定は内部で UTF-8 → EUC-JP という変換をもって行われているため ◦ 文字コード推測はあくまで推測であって常に期待する結果を得ることはできないもの ◦ nkf 利用時は可能な限り明示的に入力の文字コードを指定すべきと思った • 文字コードについて入門した ◦ nkf のソースコードはなんとなく読める程度にはなった ▪ ラピュタでいうムスカ大佐状態 ▪ 「読める!読めるぞ!!」 ◦ 何事も基礎は大事 ◦ 文字コードに関連したセキュリティについて整理したいという背景もあった ▪ 文字コードに起因した SQL インジェクションが発生する機序の話とか