tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルMidB関数
記事No13684
投稿日: 2009/05/16(Sat) 16:55
投稿者16万
VB6.0 を使用していますが、
あるテキストファイルを line input で1行ずつ読み込んで、midB関数で一部分を切取りたいのですが、MidB関数がうまく動いてくれません。

 "   ああ-1  いい"  という文字列に対して(「ああ」の前に半角スペース×3 「-1」のあ  と半角スペース×2)

この文字列A1とすると、midB(A1,4,6) で 「ああ-1」 が取り出せるはずが
半角文字(スペース)も2バイトで計算しているようで、「 ああ」を取り出してしまいます。
MidB関数は全角は2バイト半角は1バイトで計算するはずなのになぜなのでしょうか?

[ツリー表示へ]
タイトルRe: MidB関数
記事No13685
投稿日: 2009/05/16(Sat) 17:25
投稿者nobu
以前に下記に投稿した事があります。

http://hanatyan.sakura.ne.jp/logbbs/wforum.cgi?mode=allread&no=1179&page=1680

この中でのリンク先が現在は無くなっています。

Private Sub Command1_Click()

   Dim A1 As String

   A1 = "   ああ-1  いい"

   Debug.Print MidBB(A1, 4, 6)  ' --->  [ああ-1]

   Debug.Print LenBB(A1)  ' --->  15

End Sub

Private Function LenBB(sTargetStr As String) As Long
    LenBB = 0
    If IsNull(sTargetStr) Then
        LenBB = 0
        Exit Function
    End If
    LenBB = LenB(StrConv(sTargetStr, vbFromUnicode))
End Function


Private Function MidBB(sTargetStr As String, lStrPos As Long, lLength As Long) As String
    MidBB = ""
    If IsNull(sTargetStr) Then
        MidBB = Null
        Exit Function
    End If
    MidBB = StrConv(MidB(StrConv(sTargetStr, vbFromUnicode), _
                                             lStrPos, lLength), vbUnicode)
End Function

[ツリー表示へ]
タイトルRe^2: MidB関数
記事No13687
投稿日: 2009/05/16(Sat) 18:02
投稿者魔界の仮面弁士
> この中でのリンク先が現在は無くなっています。
VB ラボ! のサイトですね。

当時も指摘されていましたが、そのサンプルはいろいろと間違っているので、
一応ツッコミを入れさせてください。


> Private Function LenBB(sTargetStr As String) As Long
>     LenBB = 0
>     If IsNull(sTargetStr) Then

IsNull(sTargetStr) が True を返す事はありえないので、
この部分の If 文は不要です。

sTrargetStr As Variant であれば意味を成しますが、その場合は
最初の LenBB = 0 の行は冗長となります。(どうせその後で上書きされてしまうため)


> Private Function MidBB(sTargetStr As String, lStrPos As Long, lLength As Long) As String
>     MidBB = ""
>     If IsNull(sTargetStr) Then

こちらも同様。Null 値を保持できるデータ型は、Variant 型だけですが、
sTargetStr は String 型であるため、IsNull(sTargetStr) は常に False です。


>         MidBB = Null

これも NG です。
String 型に Null 値を代入することはできないので、これが処理された場合、
実行時エラー「Null の使い方が不正です」が発生することになります。

ただし、先の『If IsNull(sTargetStr) Then』の条件自体が間違っているため、
実際には、この部分の代入処理が実行される事はありません。


---
で、その代替となる関数を下記に掲載しておきました。
http://hanatyan.sakura.ne.jp/patio/read.cgi?no=229

このコードを貼り付けた上で
 S = MidA(A1, 4, 6)
のようにして利用できます。

[ツリー表示へ]
タイトルRe^3: MidB関数
記事No13690
投稿日: 2009/05/17(Sun) 07:43
投稿者nobu
魔界の仮面弁士さん、何時も詳しい解説ありがとうございます。

> > この中でのリンク先が現在は無くなっています。
> VB ラボ! のサイトですね。

そうでしたね、ここのサンプルも良く参照させて頂いていました。


> 当時も指摘されていましたが、そのサンプルはいろいろと間違っているので、
> 一応ツッコミを入れさせてください。

ありがとうございます。そうとは知らずに文字列処理には何時も使っています。


> で、その代替となる関数を下記に掲載しておきました。

これはまたご親切にありがとうございます。(至れり尽くせりに感謝)
現在使用しているソースを今回ご提示のコードに置き換えをします。

[ツリー表示へ]
タイトルRe: MidB関数
記事No13686
投稿日: 2009/05/16(Sat) 17:54
投稿者魔界の仮面弁士
> あるテキストファイルを line input で1行ずつ読み込んで、midB関数で一部分を切取りたいのですが、MidB関数がうまく動いてくれません。
16bit 版である VB2、VB3、VB4(16bit) であれば、そのコードでうまくいきますが、
32bit 版である VB4(32bit)、VB5、VB6 では違う結果となります。

これは、32bit 版の Visual Basic で使われている文字コードが Shift_JIS ではなく、
すべての文字を 2 バイトで表現する「Unicode」(UTF-16)で管理されているためです。

'---------
Dim A1 As String
A1 = "   ああ-1  いい"

MsgBox Len(A1)      'VB2 では「11」、VB6 でも「11」
MsgBox LenB(A1)     'VB2 では「15」、VB6 では「22」

MsgBox MidB(A1, 4, 6)    'VB2では「ああ-1」、VB6では「???」(文字化けして表現不可)
MsgBox Mid(A1, 4, 6)     'VB2 も VB6 も「ああ-1  」
'---------


> MidB関数は全角は2バイト半角は1バイトで計算するはずなのになぜなのでしょうか?
だからこそです。32bit 版 VB では、すべての文字が 2 バイトで表されています。

詳細情報として、Visual Basic 6.0 リリースノート (Readmevb.htm) の
 「32 ビット環境での文字列操作関数の動作について」
 「32 ビットでの文字列操作の 注意事項」
 「ANSI 文字列のバイト単位の操作をする関数の例」
を参照しておいてください。


> "   ああ-1  いい"  という文字列
これは String 型ですよね。メモリ上に保持されているバイナリは、16進数表記で
 [VB2] 20 20 20 82 A0 82 A0 2D 31 20 20 82 A2 92 A2
 [VB6] 20 00 20 00 20 00 42 30 42 30 2D 00 31 00 20 00 20 00 44 30 44 30
と並んでいます。下段が 32bit 版である VB6 のメモリ配置です。


MidB(A1, 4, 6) という事は、(先頭を1とした)4バイト目から6バイト分なので、
 [VB2] -- -- -- 82 A0 82 A0 2D 31 -- -- -- -- -- --
 [VB6] -- -- -- 00 20 00 42 30 42 -- -- -- -- -- -- -- -- -- -- -- -- --
の部分が取り出される事になります。

これを String として処理するために、文字列としてデコードすると、
16 bit 版の VB と 32 bit 版の VB とでは、それぞれ
 'VB2
 S1 = Chr(&H82) & Chr(&HA0) & Chr(&H82) & Chr(&HA0) & Chr(&H2D) & Chr(&H31)
 MsgBox S1    '「ああ-1」となる。

 'VB6
 S2 = ChrB(&H00) & ChrB(&H20) & ChrB(&H00) & ChrB(&H42) & ChrB(&H32) & ChrB(&H42)
 MsgBox S2    '文字化けして「???」となる。
 S3 = ChrW(&H2000) & ChrW(&H4200) & ChrW(&H4232)
 MsgBox S3    '文字化けして「???」となる。
と処理される事になります(ちなみに、VB6 の方の S2 と S3 は同一です)。



もし、VB2 の場合と同様に、「ああ-1」と取り出したいのであれば、StrConv 関数を併用して、
Shift_JIS バイナリと Unicode バイナリの相互変換を行う必要があります。

'--------------------
Dim A1 As String
A1 = "   ああ-1  いい"

Dim SJIS As String, Cut As String, Unicode As String
SJIS    = StrConv(A1, vbFromUnicode)
Cut     = MidB(SJIS, 4, 6)
Unicode = StrConv(Cut, vbUnicode)

MsgBox Unicode    '「ああ-1」となる。
'--------------------

上記のようにすれば、望む結果になるかと思います。

ちなみにこの場合、それぞれの文字列のメモリ構成は、
 [A1]    20 00 20 00 20 00 42 30 42 30 2D 00 31 00 20 00 20 00 44 30 44 30
 [SJIS]   20 20 20 82 A0 82 A0 2D 31 20 20 82 A2 92 A2
 [Cut]   82 A0 82 A0 2D 31
 [Unicode] 42 30 42 30 2D 00 31 00
となっています。

[ツリー表示へ]
タイトル前回の件は解決されましたか?
記事No13688
投稿日: 2009/05/16(Sat) 18:36
投稿者花ちゃん
ピクチャーボックスの表示位置 - 16万 09/04/03-11:01 No.13562

上記の前回の質問は解決されたのでしょうか?
レスを貰ったら必ず返事をするようにして下さい。

[ツリー表示へ]
タイトルRe: 前回の件は解決されましたか?
記事No13695
投稿日: 2009/05/19(Tue) 09:54
投稿者16万
解決しました。
ありがとうございました。

[ツリー表示へ]