C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

MidB関数の利用について

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■84781 / inTopicNo.1)  MidB関数の利用について
  
□投稿者/ シュヴァ (1回)-(2017/08/02(Wed) 11:53:44)

分類:[.NET 全般] 

プログラムのコードををVB6からVB2010に変換する際にMidB関数が使えないとのことだったのでhttp://jeanne.wankuma.com/tips/vb.net/string/leftb.htmlの
MidBと同じ動きをする関数を参考にし、利用しました。

Public Shared Function MidB(ByVal strLine As String, ByVal iStart As Integer, ByVal iByteSize As Integer) As String

   Dim hEncoding As System.Text.Encoding = System.Text.Encoding.GetEncoding("Shift_JIS")
   Dim btBytes As Byte() = hEncoding.GetBytes(strLine)
   Return hEncoding.GetString(btBytes, iStart - 1, iByteSize)

End Function

動作自体は正しく行えているのですが変換前のプログラムより3倍ほど時間が掛るようになりました。
他の処理の時間も計測したところ、変換前と変わらなかったのでこの関数を利用している処理が原因なのは確かなようです。
一気に読み込んでまとめて処理ということはせず、一行ずつ処理を行いたいです。何か対処法はありますでしょうか?

引用返信 編集キー/
■84788 / inTopicNo.2)  Re[1]: MidB関数の利用について
□投稿者/ 魔界の仮面弁士 (1374回)-(2017/08/02(Wed) 15:23:15)
No84781 (シュヴァ さん) に返信
> MidBと同じ動きをする関数を参考にし、利用しました。
本来の MidB は、バイナリ単位でデータを切り出すものですね。
旧VBの String 型は、「UTF-16 ではないバイナリ」も格納できたので、
MidB に文字列を渡せるようになっています。(16bit版 VB の名残りとも言えるかも)

一方、.NET の String は UTF-16 文字列しか格納できないため、
まったく同じものにはなりません。そのため、Encoding クラスを経由して、
文字列をバイナリに置き換えるという作業が必要になるわっています。

たとえば、読み込む元データが「文字列」ではなく、「Shift_JIS なファイル」等であるなら、
Byte 配列のまま読み出しておき、それを渡すようにすれば(あるいは Stream を渡しても良い)、
GetBytes 変換が不要となり、GetString だけで処理できるので、高速化するかも知れません。
(データ内容によっては、むしろ低速化するかもしれませんが)


> 他の処理の時間も計測したところ、変換前と変わらなかったのでこの関数を利用している処理が原因なのは確かなようです。
GetBytes にかかる負荷と GetString にかかる負荷は、それぞれどの程度なのでしょうか?


> 一気に読み込んでまとめて処理ということはせず、一行ずつ処理を行いたいです。
一気に読み込んで、とありますが、strLine にはどのぐらいの量の文字列が渡されるのでしょうか。
また、一行ずつ渡したいなら、文字通り行単位で区切って渡せば良いと思いますが、
行単位で試してみていないのは、何か技術的な問題があるのでしょうか。
引用返信 編集キー/
■84789 / inTopicNo.3)  Re[1]: MidB関数の利用について
□投稿者/ shu (1047回)-(2017/08/02(Wed) 15:42:54)
No84781 (シュヴァ さん) に返信

> 動作自体は正しく行えているのですが変換前のプログラムより3倍ほど時間が掛るようになりました。
> 他の処理の時間も計測したところ、変換前と変わらなかったのでこの関数を利用している処理が原因なのは確かなようです。
> 一気に読み込んでまとめて処理ということはせず、一行ずつ処理を行いたいです。何か対処法はありますでしょうか?
ファイルから読み込んでMidBを行っているとしたらそのファイルは固定長形式で保存されているものなのでしょうか?
だとすると1行を読み込むのにテキストと開いてReadLineするのではなく、バイナリ形式で開いて1行分のバイト数を
バイト配列に読み込むようにした方がよいです。1行分がそれほど多くなければ数行分一度に読み込めばさらなる速度改善に
つながります。各フィールドの内容はバイト配列の1行分の内決まった位置のバイト列を取得し文字列に変換すればよいです。
引用返信 編集キー/
■84812 / inTopicNo.4)  Re[2]: MidB関数の利用について
□投稿者/ シュヴァ (2回)-(2017/08/04(Fri) 11:34:26)
No84788 (魔界の仮面弁士 さん) に返信

回答ありがとうございます。返信が遅れてしまい申し訳ありません。

> たとえば、読み込む元データが「文字列」ではなく、「Shift_JIS なファイル」等であるなら、
> Byte 配列のまま読み出しておき、それを渡すようにすれば(あるいは Stream を渡しても良い)、
> GetBytes 変換が不要となり、GetString だけで処理できるので、高速化するかも知れません。
> (データ内容によっては、むしろ低速化するかもしれませんが)

読み込む元データは文字列になります。

>>一気に読み込んでまとめて処理ということはせず、一行ずつ処理を行いたいです。
> 一気に読み込んで、とありますが、strLine にはどのぐらいの量の文字列が渡されるのでしょうか。
> また、一行ずつ渡したいなら、文字通り行単位で区切って渡せば良いと思いますが、
> 行単位で試してみていないのは、何か技術的な問題があるのでしょうか。

行単位で処理は行っていますがなにぶん遅いので、行単位な処理を高速で行いたいのです。分かりにくくてすみません。
コードが長かったのでだいぶ端折っていますが下記のような処理を行っています。

'判別番号を取得
strRec = MidB(LineText, 1, 2)

'日付を取得
strDate = MidB(LineText, 8, 8)

'判別番号01は名前情報
If strRec = "01" Then

'判別番号99は最後のデータ
ElseIf strRec = "99" Then

'それ以外の番号は商品データ
Else

For iCnt = 1 To 10

'商品番号を取得
strKomWo = MidB(LineText, 21 + (iCnt - 1) * 23, 5)

'入力データを取得
strKekW = MidB(LineText, 28 + (iCnt - 1) * 23, 8)

'コメント1を取得
strCmt1W = MidB(LineText, 38 + (iCnt - 1) * 23, 3)

'コメント2を取得
strCmt2W = MidB(LineText, 41 + (iCnt - 1) * 23, 3)

PrintLine(FileNo3, strDate & "," & strKomWo & "," & strKekW & "," & strCmt1W & "," & strCmt2W)

Next

データの前に判別番号が書かれており、01で商品名、99でその商品の最後のデータであることを示しています。それ以外の02,03などの番号はその商品の詳細データであることを示しています。
引用返信 編集キー/
■84813 / inTopicNo.5)  Re[2]: MidB関数の利用について
□投稿者/ Hongliang (561回)-(2017/08/04(Fri) 11:45:06)
同じ文字列に対して何度もMidBを行う必要があるのなら、先にその文字列に対してEncoding::GetBytesをしておき、MidBするときはEncoding::GetStringすればいいだけにするとか。
引用返信 編集キー/
■84814 / inTopicNo.6)  Re[2]: MidB関数の利用について
□投稿者/ シュヴァ (4回)-(2017/08/04(Fri) 12:05:44)
No84789 (shu さん) に返信

回答ありがとうございます。

> ファイルから読み込んでMidBを行っているとしたらそのファイルは固定長形式で保存されているものなのでしょうか?

ファイルは固定長でたまに数字の羅列中に文字が混じります。

01 759237492875 名前
02 481754431531 32143465 314151516 020018520
03 3153156521 13413414 890464サンプル 431425656
04 511246151511 21431414 3141356444 140254668
99 42635654366

数字はでたらめで元データはまだ長いですが上記のようになります。01から99まででデータひとつ分となります。
行数は固定ではなく5行だったり8行だったりします。

> だとすると1行を読み込むのにテキストと開いてReadLineするのではなく、バイナリ形式で開いて1行分のバイト数を
> バイト配列に読み込むようにした方がよいです。1行分がそれほど多くなければ数行分一度に読み込めばさらなる速度改善に
> つながります。各フィールドの内容はバイト配列の1行分の内決まった位置のバイト列を取得し文字列に変換すればよいです。

バイト配列を使いまとめて処理できるようやってみます。
行数が固定ではないのですが、商品一個分のデータをまとめて処理することは可能でしょうか?
引用返信 編集キー/
■84816 / inTopicNo.7)  Re[3]: MidB関数の利用について
□投稿者/ PANG2 (187回)-(2017/08/04(Fri) 12:49:17)
MidBを高速化してみました。

    Public Shared Function MidB(ByRef strLine As String, ByVal iStart As Integer, ByVal iByteSize As Integer) As String

        Static Dim lastStr As String
        Static Dim btBytes As Byte()
        Static Dim hEncoding As System.Text.Encoding = System.Text.Encoding.GetEncoding("Shift_JIS")

        If strLine <> lastStr Then
            lastStr = strLine
            btBytes = hEncoding.GetBytes(strLine)
        End If
        Return hEncoding.GetString(btBytes, iStart - 1, iByteSize)
    End Function

引用返信 編集キー/
■84818 / inTopicNo.8)  Re[3]: MidB関数の利用について
□投稿者/ シュヴァ (6回)-(2017/08/04(Fri) 13:19:22)
No84813 (Hongliang さん) に返信

回答ありがとうございます。

> 同じ文字列に対して何度もMidBを行う必要があるのなら、先にその文字列に対してEncoding::GetBytesをしておき、MidBするときはEncoding::GetStringすればいいだけにするとか。

Dim hEncoding As System.Text.Encoding = System.Text.Encoding.GetEncoding("Shift_JIS")
Dim btBytes As Byte()

'行の数だけ繰り返し
While (k < LineNumber)

 LineText = LineData(k)
 btBytes = hEncoding.GetBytes(LineText)

 '判別番号を取得
 strRec = strRec = hEncoding.GetString(btBytes, 0, 2)

 '日付を取得
 strDate = hEncoding.GetString(btBytes, 7, 8)

 '判別番号01は名前情報
 If strRec = "01" Then

 '判別番号99は最後のデータ
 ElseIf strRec = "99" Then

 'それ以外の番号は商品データ
 Else

 For iCnt = 1 To 10

 '商品番号を取得
 strKomWo = hEncoding.GetString(btBytes, 20 + (iCnt - 1) * 23, 5)

 '入力データを取得
 strKekW = hEncoding.GetString(btBytes, 27 + (iCnt - 1) * 23, 8)

 'コメント1を取得
 strCmt1W = hEncoding.GetString(btBytes, 37 + (iCnt - 1) * 23, 3)

 'コメント2を取得
 strCmt2W = hEncoding.GetString(btBytes, 20 + (iCnt - 1) * 23, 3)

 PrintLine(FileNo3, strDate & "," & strKomWo & "," & strKekW & "," & strCmt1W & "," & strCmt2W)

 Next

End While

上記のようにやってみましたが変わりませんでした。やり方がおかしいのでしょうか?

引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ