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
260
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
lldbを使ってCRubyの中を覗く
kozy4324
0
19
Lightning近況報告
kozy4324
0
300
龍昌餃子で理解するWebサーバーの並行処理モデル - 東葛.dev #9
kozy4324
1
320
Rubyで作る論理回路シミュレータの設計の話 - Kashiwa.rb #12
kozy4324
1
610
Rubyで作る論理回路シミュレータ - Shinjuku.rb #99
kozy4324
0
130
Steep導入したいRTA - Kashiwa.rb #11
kozy4324
0
240
これまで細々と作成したGemの紹介をします - Kashiwa.rb #9
kozy4324
0
310
東京Ruby会議12のお手伝いしてきた話
kozy4324
0
140
個人開発発表 LT - Shinjuku.rb #97
kozy4324
0
850
Other Decks in Technology
See All in Technology
作り直せるコードは迅速に 作り直せないDBは慎重に - AI時代のプロダクトエンジニアが「判断の不可逆性」で開発速度を変える話
kinosuke01
0
180
DINO-EdgeQuery:Edge-First Polygon Decoding for Building Footprint Extraction from Satellite Imagery
lehupa
0
140
Does an AI Watermark Survive Translation?
machinetranslation
0
520
[DroidKaigi 2026] Making UI specifications visible: Android UI development in the AI agent era supported by Compose Screenshot Testing and galleries
syarihu
0
530
Hub & Spoke 環境のネットワークルーティングを分解してみる
tsuyataku
1
520
Backstageでつくるセルフサービスな社内開発基盤
kikunosuke75
1
230
AndroidでHDRメディアを「壊さずに」扱う
chigichan24
0
370
[RSJ26] Hierarchy-Aware Multimodal Retrieval-Augmented Generation for Embodied Question Answering
keio_smilab
PRO
1
170
Nav2、Nav3 ... はたまた自作?〜 作って理解する Nav3 の設計意図 〜 / Nav2, Nav3 ... or Build Your Own? — Understanding Nav3's design intent by building it from scratch
yanzm
0
200
Bet AI Day 2026丨バクラク Autopilot、業務システムの再設計
layerx
PRO
2
1.1k
【視聴者参加型!】AWSセキュリティアンチパターンクイズ
syoshie
0
210
Bet AI Day 2026丨AIによって本質に戻るシステムリスク管理
layerx
PRO
0
790
Featured
See All Featured
Amusing Abliteration
ianozsvald
1
280
Discover your Explorer Soul
emna__ayadi
2
1.3k
GitHub's CSS Performance
jonrohan
1033
470k
What does AI have to do with Human Rights?
axbom
PRO
1
2.4k
Paper Plane
katiecoart
PRO
2
53k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
230
The Pragmatic Product Professional
lauravandoore
37
7.4k
Mind Mapping
helmedeiros
PRO
1
340
Done Done
chrislema
186
16k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
410
Navigating Weather and Climate Data
rabernat
0
510
Automating Front-end Workflow
addyosmani
1369
210k
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 インジェクションが発生する機序の話とか