VB.NETでもAsc関数で文字コードを取得したい
はじめに
Visual Studioのインテリセンスを眺めているとAsc
やAscW
といった関数を目にします。
説明文をざっと見る限り文字に対応する文字コードを返すとあるのですが、
- 文字コードとは一体どのコード体系を指してるのか
Asc
とAscW
は何が違うのか- 当該コード体系に無い文字を指定したらどうなるのか
が気になるわけです。 まぁ、今まで気になっても調べてなかったのですが。
しかしながら文字コードマスターを目指している弊社としましてはこの違いをはっきりさせておかないといけないわけです。 なんでしょう文字コードマスターって。全世界のコード体系の図鑑を完成させる旅にでも出るんですかね。
既定のコードポイントとUnicode
まぁ、このようなケツに1文字付くか付かないかの違いしかない関数は大抵レガシーVBが元になってることが多いので、ヤフーでググってみると
Asc
は既定のコードページのコードポイント、AscW
はUnicodeにおけるコードポイント
ってらしいです。
まぁ、『ハイ、そうでした。』じゃあ味気ないので適当なサンプルコードをぶち込んでみましょう。
Console.WriteLine("{0,8} {0:X4}", Asc("A")) Console.WriteLine("{0,8} {0:X4}", Asc("ア")) Console.WriteLine("{0,8} {0:X4}", Asc("あ")) Console.WriteLine("{0,8} {0:X4}", AscW("あ"))
65 0041 177 00B1 -32096 FFFF82A0 12354 3042
まぁ、そうなるな。
日本語版Windowsでは既定のコードポイントはCP932。つまりShift_JISです。 概ねShift_JISでのエンコード結果となっています。
しかし、Asc("あ")
では上位2バイトがなぜかFFFF
になってます。
なんででしょう。色々コードを見てみたのですがちょっとこれはなぜかわかりませんでした。
フォールバック
ここで『ハイ、これでコードポイントを取得できました。』で終わるわけがありません。
次に気になるのがShift_JISに含まれない文字のコードポイントを取得しようとした場合の挙動です。
内部でSystem.Text.Encoding
を使用しているので最低でもCP932
では最適フォールバックされるはずです。
Console.WriteLine("{0,8} {0:X4}", Asc("A")) Console.WriteLine("{0,8} {0:X4}", Asc("Å")) Console.WriteLine("{0,8} {0:X4}", Asc(ChrW(&H2681)))
文字コード実装回で最適フォールバックのテスト用の文字をまた持ってきました。
65 0041 65 0041 63 003F
こいつ、やっぱり最適フォールバックしやがった。
ついでに半濁点のか『か゜』*1も試してみましょう。 コレはJIS X 0213では合成済み文字として1つのコードポイントを割り当ててあるので出来ればそのコードポイントが欲しいところですね。 まぁ、実装を見る限りケロっと『か』のコードポイントを返してくるはずですけどね。*2
Console.WriteLine("{0,8} {0:X4}", Asc("か゜"))
-32087 FFFF82A9
うん、知ってた。
Unicodeでは『ぱ』行を除いた半濁点は単一の文字としては扱えず、合成文字としてしか扱えません。
つまり『か』+『゜』となるわけです。
Asc
ではSystem.String
が渡されたら最初の1文字だけをエンコーダに渡しますからエンコーダに渡された時点で『か』となってしまうわけです。
まとめ
今回もなんか文字コードの闇を覗き込んでしまった感じとなりました。 なんか文字コードって調べれば調べるほど闇が見えますね。 まぁ、これでもUnicodeの登場で随分と楽になったんですけどね。*3
Asc
は既定のコードページのコードポイントをカジュアルに取得できるわけですけど、Unicode全盛期のこの時代にわざわざUCS以外の符号化文字集合を使う理由もあんまり無いかもしれません。
.NETの内部コードはUTF-16が使われてますし、外部コードはUTF-8を使えば大体の場面においていい感じにアレがアレになりますしお寿司。
余談ですがExcel 2000ではCSVは既定のコードページでエンコされたファイルしか読めないという犬も食わない仕様がありました。
おわり