読者です 読者をやめる 読者になる 読者になる

VB.NETでもAsc関数で文字コードを取得したい

はじめに

Visual Studioのインテリセンスを眺めているとAscAscWといった関数を目にします。

説明文をざっと見る限り文字に対応する文字コードを返すとあるのですが、

  • 文字コードとは一体どのコード体系を指してるのか
  • AscAscWは何が違うのか
  • 当該コード体系に無い文字を指定したらどうなるのか

が気になるわけです。 まぁ、今まで気になっても調べてなかったのですが。

しかしながら文字コードマスターを目指している弊社としましてはこの違いをはっきりさせておかないといけないわけです。 なんでしょう文字コードマスターって。全世界のコード体系の図鑑を完成させる旅にでも出るんですかね。

既定のコードポイントとUnicode

まぁ、このようなケツに1文字付くか付かないかの違いしかない関数は大抵レガシーVBが元になってることが多いので、ヤフーでググってみると

Ascは既定のコードページのコードポイント、AscWUnicodeにおけるコードポイント

ってらしいです。

ってことはVBでもこれに従ってるんじゃねえの?ってことでソースコードを覗いてみたらやっぱりその通りでした (2016/3/13/現在、リンク先が消失していました。)

まぁ、『ハイ、そうでした。』じゃあ味気ないので適当なサンプルコードをぶち込んでみましょう。

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

か゜ - Wikipedia

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は既定のコードページでエンコされたファイルしか読めないという犬も食わない仕様がありましたね。 もうすぐWindows 10がリリースされるこのご時世にWindows XP + Office 2000のスーパーコンボをキメてる会社なんて無いと思いますけど(チラッ

そう言えばAscWサロゲートペアをぶち込んだ時の挙動も気になりますが、なんかもう眠いので今回はここまで。

おわり

*1:表示上U+309Cとして書いてます

*2:そもそもCP932はJIS X 0208 with 愉快な仲間たちですからそもそも半濁点のかなんで存在しないけどね

*3:一部問題領域は除く