strConvのunicodeについて への返答

投稿で使用できる特殊コードの説明。(別タブで開きます。)
本名は入力しないようにしましょう。
投稿した後で削除するときに使うパスワードです。返答があった後は削除できません。
返答する人が目安にします。相手が小学生か社会人かで返答の仕方も変わります。
最初の投稿が質問の場合、質問者が解決時にチェックしてください。(以降も追加書き込み・返信は可能です。)
※「過去ログ」について書くときはその過去ログのURLも書いてください。

以下の返答は逆順(新しい順)に並んでいます。

投稿者 コロン  (社会人) 投稿日時 2019/10/29 22:08:25
>魔界の仮面弁士さん

お返事ありがとうございます。

  >もしも『文字列型変数』の部分が As Variant ではなく As String の場合は、
    「0」「1」「2」のいずれかになるでしょう。この点の認識は相違ないでしょうか?

はい、その通りです。

String型の変数に無理にいれようとしてしまっていましたが、魔界の仮面弁士さんのお返事を拝読し
何とか処理を完成させることができました。有難うございました。
大変ご丁寧に分かりやすくお書きくださいましたが一度で覚えられなそうなので
定期的に拝読させていただきます。
有難うございました!


>KOZ さん

お返事ありがとうございます。
HP拝見しました。マイグレーションはたくさんの方がぶつかる難関だと思いますが、救世主のような
サイトでした!有難く拝読させていただきます!
有賀ようございました!

投稿者 KOZ  (社会人) 投稿日時 2019/10/29 21:59:24
i以前、VB6.0 から VB.NET へマイグレーションしたとき、以下のようなことをしました。

データを Byte 配列で保持する VBString クラスを作成
http://kozhouse.homeip.net/dotnet/VBStrings/03/

これを使用して

StrConv の互換関数 StrConvExを作成
http://kozhouse.homeip.net/dotnet/VBStrings/05/

LenB,LeftB,MidB,RightB を実装
http://kozhouse.homeip.net/dotnet/VBStrings/06/

C# で書いてありますが、VB.NET に変換してくれるツールやサイトもありますので、よろしければ使ってみてください。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2019/10/29 01:03:21
> Dim length As Integer = System.Text.Encoding.Default.GetCharCount(binary)

ひとつ書き忘れ。
Shift_JIS データの文字数を数えるにあたり、指定したバイナリが
「Shift_JIS としてありえないデータだった場合にどうすべきか」を考える必要があります。


Dim shiftJisBinary() As Byte = ……

があったとして、この配列が指し示す「文字数」をカウントする処理を考えてみます。


Shift_JIS として不正なデータだったらエラーとする場合は ExceptionFallback を使います。

Dim ef = System.Text.EncoderFallback.ExceptionFallback
Dim df = System.Text.DecoderFallback.ExceptionFallback

Dim enc = System.Text.Encoding.GetEncoding("Shift_JIS", ef, df)
Dim length As Integer = enc.GetCharCount(shiftJisBinary)


あるいは、Shift_JIS で表現できないバイト列が混入していた場合において
それをエラーとするのではなく、代替文字で置き換える(いわゆる文字化け)のであれば、
ReplacementFallback を使い、変換失敗時の代替文字を指定します。

Dim ef As New System.Text.EncoderReplacementFallback("⊛") '代替文字を指定
Dim df As New System.Text.DecoderExceptionFallback()

Dim enc = System.Text.Encoding.GetEncoding("Shift_JIS", ef, df)
Dim length As Integer = enc.GetCharCount(shiftJisBinary)



なお、最初の回答に書いた .GetEncoding("Shift_JIS") という指定方法の場合は、
ReplacementFallback が指定されたものとして処理されます。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2019/10/29 00:47:29
VB6 と VB.NET の文字列型には、大きな違いがひとつあります。

VB6 の String 型は、「任意のバイナリデータ」を格納できるようになっています。
既定では UTF-16 でエンコードされたバイナリが入っていますが、実際にはそれ以外、
たとえば Shift_JIS でエンコードされたバイナリを格納することもできますし、やろうと思えば
exe ファイルのバイナリデータを蓄えさせることだって可能です。

それに対し、VB.NET の String は、常に UTF-16 相当で符号化されたデータしか保持できません。
故に、文字列型変数に Shift_JIS エンコードのデータを格納することは、原理的に不可能です。

-------

さて。今回提示頂いた VB6 の
 Len(StrConv(MidB(文字列型変数, 20, 2), vbUnicode))
というコードが返しうる値は、「Null」「0」「1」「2」のいずれかです。

もしも『文字列型変数』の部分が As Variant ではなく As String の場合は、
「0」「1」「2」のいずれかになるでしょう。この点の認識は相違ないでしょうか?

-------

上記処理においては、「文字列型変数」に入っている値は
「Shift_JIS でエンコードされたバイナリデータ」であることが期待されます。

そして、MidB 関数によって、そのバイナリデータから、
「19 バイト目から20バイト目」にあたる 2 バイト分を切り出しています。
※先頭を 0 バイト目としてカウントした場合。

そしてそれを、StrConv(, vbUnicode) によって、符号化方式を Shift_JIS から UTF-16 へと
変換してデコードすることで「文字列」として取り出し、最後にそれを Len 関数で
文字数を取得するという流れです。

もし、MidB での切り出す位置が悪く、Shift_JIS の全角文字が分断されるようなことがあれば、
その後の StrConv での vbUnicode 変換は文字化けすることになります。

-------

話を VB.NET に移しましょう。

冒頭で述べた通り、VB.NET の String 型には、
「Shift_JIS でエンコードされたバイナリデータ」を格納することができません。
VB.NET において、String 型で受け取れるのは Unicode 文字列のみです。

ですから、そもそも最初のデータの入り口は
 Dim strData As String = Shift_JIS でエンコードされたバイナリデータ
ではなく、
 Dim binData() As Byte = Shift_JIS でエンコードされたバイナリデータ
でなければなりません。


そうすると、その後の MidB(**, 20, 2) に相当する処理というのは、
binData(19)~binData(20) の位置を切り出す処理であるといえます。
切り出すためのコードはいろいろな書き方がありますが、たとえば
  Dim binary(1) As Byte
  Array.Copy(binData, 19, binary, 0, 2)
あるいは、
  Dim binary() As Byte = binData.Skip(19).Take(2).ToArray()
などと書けます。

これで、Shift_JIS バイナリから 2 バイト分を切り出せたので、あとはそれが
Shift_JIS として見た場合の何文字分であるかを調べるだけです。
これには、
  Dim length As Integer = System.Text.Encoding.Default.GetCharCount(binary)
というコードを使います。GetCharCount は文字通り「文字数」を数えるメソッドです。

上記の System.Text.Encoding.Default は、日本語環境では「Shift_JIS 符号化」を表しています。
あるいは System.Text.Encoding.Default の代わりに、
System.Text.Encoding.GetEncoding(932) もしくは
System.Text.Encoding.GetEncoding("Shift_JIS") と書くこともできます。

他言語版の Windows で動かした場合にも Shift_JIS で処理されることを保証したいなら、
Default ではなく GetEncoding で指定した方が良いでしょう。
投稿者 コロン  (社会人) 投稿日時 2019/10/28 22:12:01
初めまして、コロンと申します。

現在、VB6のコードからVB.NETのコードへの移行作業をしておりますが
Len(StrConv(MidB(文字列型変数, 20, 2), vbUnicode))
をVB.NETでどのように書いていいのかが分かりません

vbUnicodeにコンバートするということはByte型変数に値を入れないといけないと思いますが
Byte型変数に値を入れた後にどのように文字を切り取ればいいのか、またこの書き換え方法が合っているのかか
わかりません

何卒ご教示のほど、よろしくお願いいたします