文字列→構造体へキャストは可能?

解決


一馬  2006-12-14 01:28:32  No: 134563

Line Inputで読込んだString型の文字列があります。
特に区切り文字がない、固定長のデータなので、1個1個数字を指定して
必要な部分を取出せばいいのですが、数が多いのでそのまま構造体の変数
として見る事は出来ないか?と考えています。  VB6で可能でしょうか?

<イメージ例>

Type KOU_TEST
    Double1 As String * 1
    Code1   As String * 5
    Double2 As String * 1
    Conmma1 As String * 1
    Double3 As String * 1
    Code2   As String * 5
    Double4 As String * 1
    Conmma2 As String * 1
    Double5 As String * 1
    Code3   As String * 5
    Double3 As String * 1
End Type

Dim aaa As KOU_TEST
Dim bbb as String

bbb=""aaa","bbb","ccc""

aaa=bbb ←この様なイメージでコピーしたい。

その後、下記の様に通常の構造体として、必要な部分のみ利用したいです。

aaa.Code1
aaa.Code2
aaa.Code3


大吉末吉  2006-12-14 01:59:40  No: 134564

> Type KOU_TEST
って、事はVB6までですよね?
でしたら、「構造体」では無く、「ユーザー定義型」ですね。

文字列型からユーザー定義型へのキャスト(コピー)はできませんが、
ユーザー定義型からユーザー定義型ならできます。

つまり、
------------------------
Private Type X
    X As String * 23
End Type
------------------------
の様な、同じサイズのユーザ定義型を、もう一つ用意しておけば、
「LSet ステートメント」でコピーできます。


大吉末吉  2006-12-14 02:04:29  No: 134565

あれ、
> 特に区切り文字がない、固定長のデータなので
って事なのに、

> bbb=""aaa","bbb","ccc""
って?

区切り記号(,)はあるし、*5のはずなのに、3文字しかない。


我龍院  2006-12-14 02:25:53  No: 134566

Open "hogege.txt" For Random As #intFileNum Len = Len(aaa)
Get #intFileNum, 1, aaa
直接ランダムアクセスで読んではいけないのかな。


一馬  2006-12-14 05:28:11  No: 134567

【大吉末吉様】

>ユーザー定義型からユーザー定義型ならできます。
>「LSet ステートメント」でコピーできます。

ありがとうございます。これでやってみます!

>区切り記号(,)はあるし、*5のはずなのに、3文字しかない。

すいません。
説明用に作ったデータに誤りがありました。
5→3で、(,)はありません。

【我龍院様】

>Open "hogege.txt" For Random As #intFileNum Len = Len(aaa)
>Get #intFileNum, 1, aaa

ランダムアクセスで読込んだのですが、レングスはあわせた筈なのに、
上手く各項目に値がセットされなかった次第です。
そこで、LineInputでスキャンし、スキャン後のデータを構造体へキャ
スト出来ないかなと思っておりました。

ちなみに、固定長文字を切り出す時、不思議な現象が発生してます。

Dim aaa,bbb as String

aaa = "12345678テストU,H,A,G,K,B,ph                                    "",123456789"
bbb = MidB(aaa, 1, 128)

この様に、変数aaaの文字列の中から、最初のダブルクォーテーション部分(64バイト)の文字をMidB関数で切り出し、bbb関数へ格納しようとしています。
UNICODEになるらしいので、倍の128を指定してるのですが、ダブルクォーテーション以降の文字も入ってしまいます。
全部半角文字と区切り文字が混在する、固定長文字列の切り出しは、どうすべきなのでしょうか?


我龍院  2006-12-14 18:31:13  No: 134568

ウン−、混乱ですね。
一つずつやっていきましょう。
>Dim aaa,bbb as String
これは  
Dim aaa as String , bbb As String ですよね。

>aaa = "12345678テストU,H,A,G,K,B,ph                                    "",123456789" 
「""」を「"〜"」の中で使うと、最初の「"」はエスケープキャラクタになります。
詳しくは、MSDNの「文字列内のクオーテーション マーク」を参照してください。


魔界の仮面弁士  2006-12-14 18:50:28  No: 134569

> ランダムアクセスで読込んだのですが、レングスはあわせた筈なのに、
> 上手く各項目に値がセットされなかった次第です。
VB6 の文字列は、Unicode として保持されるとは言っても、ファイルへの
入出力時などにおいては、VB2 の文字列同様、Shift_JIS に変換されます。

VB6 の場合、String * 2 が「2 文字」を意味しますので、漢字等が
含まれるデータの場合、文字コード変換に伴うデータサイズのずれを
考慮せねばなりません。

そのため、
> Open "hogege.txt" For Random As #intFileNum Len = Len(aaa)
で開いた場合、問題が出てくるかと思われます。


魔界の仮面弁士  2006-12-14 19:02:46  No: 134570

固定長文字列型を含むユーザ定義型の、ファイル出力テスト

-------------------------
Option Explicit

Private Type T
    S As String * 3
End Type

Private Sub Form_Load()
    Command1(0).Caption = "バイナリ"
    Command1(1).Caption = "ランダムLen=6"
    Command1(2).Caption = "ランダムLen=3"
    Check1.Caption = "メンバのみ出力"
    Check1.Value = vbChecked
End Sub

Private Sub Command1_Click(Index As Integer)
    Dim FNo As Integer
    FNo = OpenFile(Index)
    
    PutData FNo, "012"
    PutData FNo, "あいう"
    PutData FNo, "345"

    Close FNo
End Sub

Private Function OpenFile(ByVal Index As Integer)
    Const File As String = "C:\newFile.txt"
    If Dir(File) <> "" Then
        Kill File
    End If
    
    OpenFile = FreeFile()
    Dim x As T
    Select Case Index
     Case 0
        Open File For Binary Access Write As #OpenFile
     Case 1
        Open File For Random Access Write As #OpenFile Len = LenB(x)
     Case 2
        Open File For Random Access Write As #OpenFile Len = Len(x)
    End Select
End Function

Private Sub PutData(ByVal FNo As Integer, ByVal text As String)
    Dim x As T
    x.S = text
    If Check1.Value = vbChecked Then
        Put #FNo, , x.S
    Else
        Put #FNo, , x
    End If
End Sub
-------------------------

バイナリ、メンバのみ
→ "012あいう345"
→ 30,31,32,82,A0,82,A2,82,A4,33,34,35

ランダムLen=6、メンバのみ
→ "012###あいう345"  (#部は null文字)
→ 30,31,32,00,00,00,82,A0,82,A2,82,A4,33,34,35

ランダムLen=3、メンバのみ
→ (平仮名の出力時に、実行時エラー59)
→ (レコード長が一致しません。)

バイナリ、ユーザ定義型全体
→ "012あ*345"  (*部は非可読文字)
→ 30,31,32,82,A0,17,33,34,35

ランダムLen=6、ユーザ定義型全体
→ "012###あ*###345"  (#部は null 文字、*部は非可読文字)
→ 30,31,32,00,00,00,82,A0,17,00,00,00,33,34,35

ランダムLen=3、ユーザ定義型全体
→ "012あ*345"  (*部は非可読文字)
→ 30,31,32,82,A0,17,33,34,35


一馬  2006-12-14 19:06:37  No: 134571

【我龍院様】
>一つずつやっていきましょう。
ありがとうございます。

>>Dim aaa,bbb as String
>これは  
>Dim aaa as String , bbb As String ですよね。
その通りです。

>>aaa = "12345678テストU,H,A,G,K,B,ph                                    "",123456789" 
>「""」を「"〜"」の中で使うと、最初の「"」はエスケープキャラクタになります。
実際には「”」を含む文字列があり、そこの手前部分(64バイト)までを取り込もうとしています。
(「12345678テストU,H,A,G,K,B,ph                                    」←この部分)
単純に「bbb = MidB(aaa, 1, 128)」で切り出せると思っていたのですが、上手く切り出せず、質問してる次第です。
何か分かりますでしょうか?


一馬  2006-12-14 19:40:56  No: 134572

【魔界の仮面弁士様】

>VB6 の場合、String * 2 が「2 文字」を意味しますので、漢字等が
>含まれるデータの場合、文字コード変換に伴うデータサイズのずれを
>考慮せねばなりません。
>そのため、
>> Open "hogege.txt" For Random As #intFileNum Len = Len(aaa)
>で開いた場合、問題が出てくるかと思われます。

当初、ランダムアクセスを用いて下記の様なファイルをリードしようとしてました。

/*テキストファイルの中身*/
-----------------------------------------------------------------
"あああああ","かきく,AAA","”さ”,1"
"いいいいい","かき,AAAAA","”さ”,2"
"ううううう","か,AAA,BBB","”さ”,3"
-----------------------------------------------------------------

/*プログラム*/
Type KOU_SAMPL
    Double1 As String * 1
    Name1   As String * 10
    Double2 As String * 1
    Conmma1 As String * 1
    Double3 As String * 1
    Name2   As String * 10
    Double4 As String * 1
    Conmma2 As String * 1
    Double5 As String * 1
    Name3   As String * 10
    Double3 As String * 1
    Enter   As String * 2
End Type

Dim samplaaa As KOU_SAMPL

Open FNAME For Random Access Read As #Fno Len = Len(sampl)
    Get #Fno, , sampl
    Do Until EOF(Fno)
       〜
    Loop
Close #Fno

この様なファイルの場合、ランダムアクセスでのリードは不向きなのでしょうか?
「Input」や「Line Input+split関数」でも上手くできなかったので、
「Line Input+MidB関数」しかないのかな?と思い、現在に至ってます。
皆様はどうされてるのでしょうか?


一馬  2006-12-14 19:42:44  No: 134573

<補足>
Name3 As String * 10←8の間違いです。


魔界の仮面弁士  2006-12-14 19:43:00  No: 134574

文字コードを意識しましょう。

> 実際には「”」を含む文字列があり、そこの手前部分(64バイト)まで
それは、「Shift_JIS バイナリとしてみた場合の 64 バイト」ですよね。

VB6 側の String 型は、Unicode バイナリで保持されますから、
MidB でバイト単位の処理を行うのであれば、
  1. StrConv( , vbFromUnicode) を使い、Shift_JIS バイナリに変換
  2. MidB を使い、(Shift_JIS データとしての)先頭 64 バイトを取得
  3. StrConv( , vbUnicode) で、それを Unicode バイナリに復元
という手順をとらないと、意味がありませんよね。


魔界の仮面弁士  2006-12-14 19:58:05  No: 134575

> この様なファイルの場合、ランダムアクセスでのリードは不向きなのでしょうか?

その形式だとすれば、ランダムアクセスであれ、バイナリアクセスであれ、
固定長文字列型メンバではなく、バイト配列型メンバにすれば、
位置がずれることなく読み込ませることができますよ。ただし、
StrConv などで、文字コードの変換を行う必要がありますけど。

固定長文字列型メンバにすると、Shift_JIS/Unicode 変換が自動的に
行われるので、「文字数」と「Shift_JISでのバイト数」の差分から、
データにずれが生じてしまいます。バイナリアクセスならともかく、
ランダムアクセスでは、この点が致命的となります。

一方、バイト配列型メンバにすると、そうした自動変換が発生しないので、
データのずれは出ないため、ランダムアクセスでも有効です。そのかわり、
文字コードやデータ型の変換を、自分で行わなければならないという
不便さが残ります。

> 皆様はどうされてるのでしょうか?
固定長ファイルの読み方ですか。私は、バイナリアクセスを使った上で、
文字コードや型変換、さらに不正データの排除などを含めた処理を
記述することが多いですね。


我龍院  2006-12-14 20:10:13  No: 134576

>> Open "hogege.txt" For Random As #intFileNum Len = Len(aaa)
>で開いた場合、問題が出てくるかと思われます。
魔界の仮面弁士さん、ご指摘の通りだめですね。
最初の質問を見たときファイルベースで"固定長"と思いましたので。

>(「12345678テストU,H,A,G,K,B,ph                                    」←この部分)
私が調べると、「ph」までが25文字スペースが36文字計61文字となりますが。
念の為アスキーダンプしてみましたが同じですね。
49 50 51 52 53 54 55 56-31899-31912-31897 85 44 72 44 65 44 71 44 75 44 66 44 112 104 
32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 
32 32 32 32 32 32 32 32 32 34 44 49 50 51 52 53 54 55 56 57


一馬  2006-12-14 20:22:40  No: 134577

【魔界の仮面弁士様、我龍院様】

細かい情報有難う御座います。
バイナリアクセス、StrConv( , vbFromUnicode)、バイト配列型メンバ(?)は使った事ありませんが、調べてやってみます。

aaa = "12345678テストU,H,A,G,K,B,ph                                    "",123456789"
bbb = MidB(StrConv(aaa, vbFromUnicode), 1, 64)←まだ使い方間違えてるみたいですが(汗)

追って結果報告いたします。


一馬  2006-12-14 21:11:28  No: 134578

【魔界の仮面弁士様、我龍院様、大吉末吉様】

>1. StrConv( , vbFromUnicode) を使い、Shift_JIS バイナリに変換
>2. MidB を使い、(Shift_JIS データとしての)先頭 64 バイトを取得
>3. StrConv( , vbUnicode) で、それを Unicode バイナリに復元

こちら実現する事出来ました!!
「bbb = StrConv(MidB(StrConv(aaa, vbFromUnicode), 1, 64), vbUnicode)」
後は、バイナリアクセス、バイト配列型メンバ(?)をやってみます。


一馬  2006-12-15 02:52:24  No: 134579

解決にするの忘れてました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加