route127の日記: CP932においてケース変換で化ける配当漢字 2
perl -e "$_='山田';tr/R/r/;print;"
屍田
というような漢字は他にどんなものがあるかを探していた。
山田→屍田の例はWindowsプログラミングの極意(p.341)に載っていたのだが、そもそも何でそんな本を読んでいたかというと先日のAltコードを使って2バイト文字をSendKeysで流し込もうという流れからCP932で符号化された文字列の文字境界を探すヒントを探していたのだ。
この例から分かるようにCP932で符号化されたバイト列が与えられた場合文字境界を探すのは簡単ではなさそうである。
昔見たperlでのCP932にマッチする正規表現/[\x82-\x9f\xe0-\xef][\x7e\x80-\xfc]/とか使えばできるだろうか。
CP932において2バイト目が0x5Cとなる漢字が化けるというのは割と知られているが同様に2バイト目がラテン文字となる符号を持つ漢字はケース変換により冒頭の例のように化けてしまう。
これは現行のperlの内部表現でもあるUTF-8ならば回避できて、一旦内部表現に変換すればケース変換による誤変換を起こさない。
perl -MEncode -e "$_='山田';$_=decode('cp932',$_);tr/R/r/;print encode('cp932',$_);"
山田
そんな訳でケース変換によって化ける漢字は山以外にどんなものがあるのだろうかという興味につながったのだが、漢字全体では数も多いので小学生が学校で習う漢字に変換元を限って試すことにした。
Data::Kanji::Kanjidicを使えば小学1年生が習う漢字を列挙するのは以下のように書ける。
perl -MEncode -MData::Kanji::Kanjidic=parse_kanjidic,grade -e "$k=parse_kanjidic('kanjidic');print encode('cp932', join '',@{grade($k,1)})"
三目王金気一生出糸赤円足町犬竹火入村正七百力口川車九手見千下水名白草月男右上校左早中字土人田青本玉耳森文年先雨五天学子女休大空立虫日八夕二貝六林山小十花石四木音
これらをまとめるとケース変換で化ける漢字を列挙することができる。
なんかもっと面白い並べ方はありそう。
(大文字) (小文字)
---------------------
幸(8d4b) <-> 耕(8d6b)
店(9358) <-> 度(9378)
芳(9646) <-> 貿(9666)
瓢(955a) <-> 布(957a)
讐(8f51) <-> 述(8f71)
街(8a58) <-> 岳(8a78)
札(8e44) <-> 仕(8e64)
捌(8e4a) <-> 史(8e6a)
濡(9447) <-> 波(9467)
該(8a59) <-> 楽(8a79)
錬(9842) <-> 話(9862)
泥(9344) <-> 電(9364)
猶(9750) <-> 用(9770)
産(8e59) <-> 孜(8e79)
旦(9255) <-> 置(9275)
工(8d48) <-> 紘(8d68)
郡(8c53) <-> 茎(8c73)
禰(9448) <-> 派(9468)
漸(9151) <-> 倉(9171)
姥(8957) <-> 駅(8977)
忘(9659) <-> 幌(9679)
宏(8d47) <-> 紅(8d67)
紀(8b49) <-> 喫(8b69)
欝(8954) <-> 液(8974)
佑(9743) <-> 幼(9763)
年(944e) <-> 馬(946e)
禅(9154) <-> 奏(9174)
友(9746) <-> 庸(9766)
階(8a4b) <-> 殻(8a6b)
亡(9653) <-> 穆(9673)
狸(924b) <-> 談(926b)
集(8f57) <-> 舜(8f77)
濃(945a) <-> 配(947a)
群(8c51) <-> 繋(8c71)
然(9152) <-> 喪(9172)
儀(8b56) <-> 久(8b76)
鰻(8956) <-> 益(8976)
朗(984e) <-> 蕨(986e)
憂(974a) <-> 曜(976a)
飢(8b51) <-> 客(8b71)
習(8f4b) <-> 縮(8f6b)
必(954b) <-> 斌(956b)
蝕(9049) <-> 進(9069)
認(9446) <-> 杷(9466)
但(9241) <-> 誕(9261)
広(8d4c) <-> 考(8d6c)
鯖(8e49) <-> 司(8e69)
害(8a51) <-> 赫(8a71)
全(9153) <-> 壮(9173)
君(8c4e) <-> 系(8c6e)
融(975a) <-> 陽(977a)
前(914f) <-> 双(916f)
単(9250) <-> 恥(9270)
選(9149) <-> 訴(9169)
校(8d5a) <-> 鉱(8d7a)
短(925a) <-> 築(927a)
典(9354) <-> 鍍(9374)
栗(8c49) <-> 景(8c69)
開(8a4a) <-> 核(8a6a)
賎(9147) <-> 組(9167)
殖(9042) <-> 臣(9062)
羽(8948) <-> 栄(8968)
算(8e5a) <-> 斯(8e7a)
汽(8b44) <-> 掬(8b64)
徹(934f) <-> 登(936f)
山(8e52) <-> 屍(8e72)
嚢(9458) <-> 肺(9478)
刑(8c59) <-> 軽(8c79)
惨(8e53) <-> 市(8e73)
襲(8f50) <-> 術(8f70)
遊(9756) <-> 要(9776)
棚(9249) <-> 段(9269)
稗(9542) <-> 秒(9562)
炭(9259) <-> 馳(9279)
敵(9347) <-> 堵(9367)
鮮(914e) <-> 創(916e)
柚(974d) <-> 洋(976d)
記(8b4c) <-> 詰(8b6c)
軍(8c52) <-> 罫(8c72)
任(9443) <-> 把(9463)
船(9144) <-> 租(9164)
食(9048) <-> 辛(9068)
外(8a4f) <-> 覚(8a6f)
窟(8c41) <-> 径(8c61)
海(8a43) <-> 劃(8a63)
三(8e4f) <-> 姉(8e6f)
笛(934a) <-> 屠(936a)
韻(8943) <-> 営(8963)
逼(954e) <-> 貧(956e)
筆(954d) <-> 瀕(956d)
参(8e51) <-> 子(8e71)
薫(8c4f) <-> 経(8c6f)
碍(8a56) <-> 革(8a76)
康(8d4e) <-> 肱(8d6e)
達(9242) <-> 鍛(9262)
俵(9555) <-> 埠(9575)
肘(9549) <-> 品(9569)
樽(924d) <-> 知(926d)
新(9056) <-> 迅(9076)
燃(9452) <-> 排(9472)
迂(8949) <-> 永(8969)
誰(924e) <-> 地(926e)
伸(904c) <-> 人(906c)
貴(8b4d) <-> 砧(8b6d)
雑(8e47) <-> 使(8e67)
概(8a54) <-> 閣(8a74)
蟹(8a49) <-> 格(8a69)
百(9553) <-> 不(9573)
彪(9556) <-> 夫(9576)
右(8945) <-> 影(8965)
兄(8c5a) <-> 頚(8c7a)
灰(8a44) <-> 嚇(8a64)
愁(8f44) <-> 重(8f64)
竪(9247) <-> 暖(9267)
鎧(8a5a) <-> 額(8a7a)
秋(8f48) <-> 宿(8f68)
垢(8d43) <-> 皇(8d63)
勇(9745) <-> 容(9765)
慌(8d51) <-> 航(8d71)
粘(9453) <-> 敗(9473)
散(8e55) <-> 志(8e75)
豊(964c) <-> 僕(966c)
念(944f) <-> 俳(946f)
埜(9457) <-> 背(9477)
鮫(8e4c) <-> 四(8e6c)
標(9557) <-> 婦(9577)
帰(8b41) <-> 蟻(8b61)
由(9752) <-> 羊(9772)
巽(9246) <-> 断(9266)
擦(8e43) <-> 残(8e63)
添(9359) <-> 土(9379)
好(8d44) <-> 硬(8d64)
裕(9754) <-> 葉(9774)
鉄(9353) <-> 都(9373)
係(8c57) <-> 詣(8c77)
詮(9146) <-> 素(9166)
凱(8a4d) <-> 確(8a6d)
拾(8f45) <-> 銃(8f65)
就(8f41) <-> 渋(8f61)
訓(8c50) <-> 継(8c70)
優(9744) <-> 妖(9764)
森(9058) <-> 靭(9078)
貝(8a4c) <-> 獲(8a6c)
植(9041) <-> 紳(9061)
拘(8d53) <-> 行(8d73)
舛(9143) <-> 祖(9163)
孝(8d46) <-> 糠(8d66)
撒(8e54) <-> 師(8e74)
季(8b47) <-> 吉(8b67)
燦(8e57) <-> 指(8e77)
臼(8950) <-> 英(8970)
善(9150) <-> 叢(9170)
終(8f49) <-> 淑(8f69)
信(904d) <-> 仁(906d)
衆(8f4f) <-> 出(8f6f)
咳(8a50) <-> 角(8a70)
宜(8b58) <-> 休(8b78)
鼎(9343) <-> 田(9363)
絵(8a47) <-> 拡(8a67)
珊(8e58) <-> 支(8e78)
繍(8f4a) <-> 祝(8f6a)
規(8b4b) <-> 橘(8b6b)
連(9841) <-> 和(9861)
蓋(8a57) <-> 学(8a77)
皿(8e4d) <-> 士(8e6d)
労(984a) <-> 亘(986a)
起(8b4e) <-> 杵(8b6e)
辰(9243) <-> 団(9263)
訪(964b) <-> 北(966b)
傘(8e50) <-> 姿(8e70)
色(9046) <-> 診(9066)
適(934b) <-> 徒(936b)
谷(924a) <-> 男(926a)
技(8b5a) <-> 吸(8b7a)
撚(9451) <-> 拝(9471)
晒(8e4e) <-> 始(8e6e)
宇(8946) <-> 映(8966)
郵(9758) <-> 踊(9778)
雨(894a) <-> 泳(896a)
亀(8b54) <-> 逆(8b74)
触(9047) <-> 身(9067)
傾(8c58) <-> 警(8c78)
糎(9157) <-> 層(9177)
柊(9541) <-> 病(9561)
展(9357) <-> 努(9377)
州(8f42) <-> 獣(8f62)
輸(9741) <-> 預(9761)
担(9253) <-> 痴(9273)
職(9045) <-> 親(9065)
械(8a42) <-> 鈎(8a62)
渦(8951) <-> 衛(8971)
熱(944d) <-> 芭(946d)
鵬(9651) <-> 牧(9671)
坦(9252) <-> 池(9272)
界(8a45) <-> 各(8a65)
銭(914b) <-> 遡(916b)
探(9254) <-> 稚(9274)
蓬(9648) <-> 防(9668)
氷(9558) <-> 富(9578)
寧(944a) <-> 破(946a)
織(9044) <-> 薪(9064)
辱(904a) <-> 針(906a)
天(9356) <-> 砺(9376)
岨(915a) <-> 想(917a)
修(8f43) <-> 縦(8f63)
週(8f54) <-> 春(8f74)
攻(8d55) <-> 講(8d75)
的(9349) <-> 妬(9369)
心(9053) <-> 尽(9073)
祁(8c56) <-> 計(8c76)
蒐(8f4e) <-> 熟(8f6e)
気(8b43) <-> 議(8b63)
有(974c) <-> 様(976c)
路(9848) <-> 鷲(9868)
桟(8e56) <-> 思(8e76)
鱈(924c) <-> 値(926c)
謬(9554) <-> 付(9574)
住(8f5a) <-> 循(8f7a)
粂(8c48) <-> 敬(8c68)
殺(8e45) <-> 仔(8e65)
デベハトップ (スコア:0)
カタカナも化ける。
よく見かけたのは日本語非対応アプリケーションがパスの大文字小文字を変換して
デスクトップをデベハトップに変換して読み損なう問題。
CP932の境界線は、マルチバイト文字の先行バイトにも後続バイトにもなりうるバイト値があるので、
それが連続しているケースでは頭から追っかける以外に方法はない。
シングルバイト文字の範囲、
マルチバイト先行バイトの範囲、
マルチバイト後続バイトの範囲、ちゃんと書き出せば判別可能な条件もわかると思うよ。
UTF-8は最上位ビットでシングルバイト判定、上から二桁目で先行後続の判別が固定で出来るのありがたいよね。
しかも先行バイトはそれだけで何バイト文字かも分かるときた。バイト効率は悪いけど。
Re: (スコア:0)
CP932を処理するときはCPANのmbを使えば文字化けせずに済む。もちろんUTF-8ならこの苦労はない。