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
25
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
You Have Agency(サンキュー、Ruby)
snoozer05
PRO
4
620
Draft AIエージェントの トークン消費を最小化する 8つの原則
kinopeee
6
1.9k
Autonomous AI Lakehouse - Live AI Hubから始めるセキュアなAIデータ活用 -
oracle4engineer
PRO
2
180
LLMの知識とAIエージェント
happysamurai294
0
130
Patterns in AI Driven Software Development
akosma
PRO
0
380
Maestro MCPとClaude Code Skillsによる自律的なE2Eテスト支援
asmz
0
390
素人でもできた!AIを使った短編小説創作入門
delhi09
PRO
0
250
なぜAI時代に技術記事を書くのか?どう書くのか? 〜bunの場合〜
kworkdev
PRO
0
1.1k
200人の配信コメント、 全部Jevが仕分けます 〜 マサカリガードを作ってみた 〜
katayamatg
1
470
AIに任せられるFlutterコードベースを作る 〜仕様をコードで表し、ハーネスで守る〜
myohei
1
580
Oracle Database Security 詳細解説
oracle4engineer
PRO
1
170
SLOを阻む不安
sraku2159
0
160
Featured
See All Featured
Done Done
chrislema
187
17k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
59k
Git: the NoSQL Database
bkeepers
PRO
433
67k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
300
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
33
5.5k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
730
VelocityConf: Rendering Performance Case Studies
addyosmani
331
25k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.7k
BBQ
matthewcrist
90
10k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
750
The World Runs on Bad Software
bkeepers
PRO
72
12k
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 インジェクションが発生する機序の話とか