Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
nkfのソースコードリーディングをした話 - Kashiwa.rb #2 LT
Search
Koji NAKAMURA
August 26, 2024
Technology
270
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
26
Lightning近況報告
kozy4324
0
350
龍昌餃子で理解するWebサーバーの並行処理モデル - 東葛.dev #9
kozy4324
1
390
Rubyで作る論理回路シミュレータの設計の話 - Kashiwa.rb #12
kozy4324
1
640
Rubyで作る論理回路シミュレータ - Shinjuku.rb #99
kozy4324
0
130
Steep導入したいRTA - Kashiwa.rb #11
kozy4324
0
250
これまで細々と作成したGemの紹介をします - Kashiwa.rb #9
kozy4324
0
320
東京Ruby会議12のお手伝いしてきた話
kozy4324
0
150
個人開発発表 LT - Shinjuku.rb #97
kozy4324
0
960
Other Decks in Technology
See All in Technology
Patterns in AI Driven Software Development
akosma
PRO
0
430
LLMの知識とAIエージェント
happysamurai294
0
150
アクセラレーターで実現するServiceNow活用の高速化 / ServiceNow World Forum 2026
visional_engineering_and_design
0
120
AI時代の開発はウォーターフォールに回帰する? / development-with-ai-back-to-wf
okamototakuyasr2
0
170
Consistency for mere mortals - A gentle guide to consistency
ufried
0
110
Snowflake でできることが増えたら、 ABAC が必要になった
kaeton
0
130
なぜ東京にいる私が、新潟の技術コミュニティを運営するのか by 八雲慎之助
yakumo
0
210
You Have Agency(サンキュー、Ruby)
snoozer05
PRO
5
640
re:Invent の去年のスケジュールを公開します!
miu_crescent
PRO
0
150
Flutter Webを「SDK」として配る — 50以上のゲームを支える埋め込みアーキテクチャ
masayukisuda
0
170
【Oracle AI SPOTLIGHT ウェビナー】事例から見る!なぜOCIが選ばれたのか ― AI時代のクラウド戦略を紐解く ―
oracle4engineer
PRO
1
150
新卒エンジニア、 介護士になる
ryu1013
1
660
Featured
See All Featured
エンジニアに許された特別な時間の終わり
watany
109
250k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
35
2.9k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
550
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
310
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
5
880
Claude Code のすすめ
schroneko
67
230k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
490
Speed Design
sergeychernyshev
33
2.2k
The agentic SEO stack - context over prompts
schlessera
0
990
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.3k
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 インジェクションが発生する機序の話とか