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
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
22
Lightning近況報告
kozy4324
0
310
龍昌餃子で理解するWebサーバーの並行処理モデル - 東葛.dev #9
kozy4324
1
370
Rubyで作る論理回路シミュレータの設計の話 - Kashiwa.rb #12
kozy4324
1
620
Rubyで作る論理回路シミュレータ - Shinjuku.rb #99
kozy4324
0
130
Steep導入したいRTA - Kashiwa.rb #11
kozy4324
0
240
これまで細々と作成したGemの紹介をします - Kashiwa.rb #9
kozy4324
0
320
東京Ruby会議12のお手伝いしてきた話
kozy4324
0
140
個人開発発表 LT - Shinjuku.rb #97
kozy4324
0
940
Other Decks in Technology
See All in Technology
Databricksメトリクスビューはじめてのもくもく会
taka_aki
0
150
Amazon Bedrock Agents ClassicからAmazon Bedrock AgentCoreへ移行した際、ガードレール設定が2箇所に割れた話
matsunobu
0
160
Incremental HTTP
kazuho
5
1.9k
AI 時代の Azure エンジニアリング ~ 私たちは何を磨き、何を任せるのか ~
chack411
1
260
サーバーフルコンピューティング?AWS Lambda
iwatatomoya
0
120
プラットフォームを「作る」、 チームに「入り込む」
sansantech
PRO
0
420
AI臭い文章とは何なのか
nasuvitz
37
76k
Account Factory for Terraformによる 標準化されたアカウント発行の自動化
pensuke628
0
120
AIに会社の文脈を理解させる技術~上流工程・非エンジニアにも広げるハーネスエンジニアリング実践~
ochtum
0
200
1万名の社員が使う認証基盤で どう信頼性を担保するか?
kairim0
0
130
MCPゲートウェイを作って運用してわかったこと — Agent時代の権限管理の現在地
mtpooh
9
2.6k
PQC移行の今 -- IETF からみた現在地
satokan
4
720
Featured
See All Featured
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
340
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
500
Art, The Web, and Tiny UX
lynnandtonic
304
22k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
470
Mind Mapping
helmedeiros
1
390
Test your architecture with Archunit
thirion
2
2.4k
Side Projects
sachag
456
43k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
270
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 インジェクションが発生する機序の話とか