いつも参考にさせていただいております。
以下を実行すると遅いです。
配列数が多くなればなるほど、あたりまえですが遅くなります。
C言語のポインタのような、何か高速に文字列を連結することはできないものでしょうか?
お願いいたします
具体的な内容は以下の通り
データをバイト配列(文字コードが入っています)へ格納
これを文字列にする
その後に文字コードをSJISに変更していこうと思っています。
※入力文字コードはJISやSJIS、UNICODEなどさまざまです
今現在のプログラム
'With ProgressBar1
' .Min = 0
' .Max = lngSize
' For i = 0 To lngSize - 1 Step 1
' strConve = strConve & Chr(bytArray(i))
' .Value = i
' DoEvents
' Next i
'End With
'Debug.Print strConve
Mid ステートメント はいかが?
編集 削除MIDは文字の切り出しだと思うのですが。。。
念のために調べたんですが知識不足でわかりませんでした。
もう少し詳しく教えていただけませんか?
VBの場合文字列が長くなると、連結にかなりの時間がかかります。
strConve = strConve & Chr(bytArray(i))
の代わりに
strConve = "A" & "A"
とやって時間を比べてみて下さい。
もしこれで時間がかなり早くなるのであれば、
時間がかかるのは、配列が多い為ではなく、文字列が
長くなり連結に時間がかかる為です。
この場合、文字列の長さを500〜1000位にして「Join」
で連結するとかなり高速になります。
Mid関数を使う場合は下記の方法で試してみてください。
With ProgressBar1
.Min = 0
.Max = lngSize
strConve = Space$(lngSize)
For i = 0 To lngSize - 1 Step 1
Mid$(strConve, i + 1, 1) = Chr$(bytArray(i))
.Value = i
DoEvents
Next i
End With
Debug.Print strConve
ありがとうございます。
nanashiさんのを実験してみました。
処理速度が後半落ちることなく実行できました。
ねろさんのjoinを使い方法とどちらが早いでしょうか。
joinの使い方を調べているのですが、併用したほうがいいのか
どちらか一方のほうがいいのかいかがでしょうか?
贅沢かもしれませんが高速になったとはいえ、最低でも今の二倍の速さがほしいです。(これを再帰的に実行していく必要があるので)
無理なものでしょうか・・・
strConv(バイト配列 , vbunicode)はなぜあんなに高速に処理できるのでしょうか?
愚問だと思いますがまったくわからないので教えてください。
お願いします。
(VB6SP6/WinXPPro/PenIII 600/256M)
今現在はこうなっています。
With ProgressBar1
.Min = 0
.Max = lngSize
strConve = Space$(lngSize)
For i = 0 To lngSize Step 1
Mid$(strConve, i + 1, 1) = Chr$(bytArray(i))
.Value = i
Label5.Caption = Format(i, "#,###,###") & "/" _
& Format(lngSize, "#,###,###") & "[" _
& Format(Int((i / lngSize) * 100), "@@@") & "%]"
DoEvents
Next i
End With
Debug.Print strConve
そのコードで一番時間のかかっている部分は、
>.Value
>Label5.Caption = Format(i, "#,###,###") & "/" _
>& Format(lngSize, "#,###,###") & "[" _
>& Format(Int((i / lngSize) * 100), "@@@") & "%]"
>DoEvents
ですよ。
速くやるならプログレスバーは不要です。
If (i / 100 = i \ 100) Then
.Value = i
Label5.Caption = Format(i, "#,###,###") & "/" _
& Format(lngSize, "#,###,###") & "[" _
& Format(Int((i / lngSize) * 100), "@@@") & "%]"
DoEvents
End If
どうしてもと言うなら、この位のことをやらなくては速くくならない。
表示は一番最後に一回だけの方がいい。
Joinでやるなら
For i = 0 To lngsize
s(i) = Chr(bytArray(i))
Next
strConve = Join(s, "")
プログレスバーは入りません。
ですがどちらが速いかは条件次第です。
ねろさん、皆様ありがとうございます!!!
比較にならないほど高速になりました!!!
本当にありがとうございます。
もうひとつ疑問が出てしまったのですが、このまま質問してもよろしいでしょうか?
ねろさんのコードに置き換えて実行したところ、Debug.Printでは正常にstrConveが表示されるのですが、ためしにテキストボックスに表示したところ、今までは正常に表示されていたものが、一行程度でそれ以降が表示されなくなりました。
(過去ログからテキストボックスの制限については理解しています)
改行コード(なのかわかりませんが)なども何か手を加えてやる必要があるのでしょうか?
実際には表示せずに処理をしていくので問題なのですが気になってしまって・・・
よろしくお願いします。
現在のコードを以下に記します。
With ProgressBar1
.Min = 0
.Max = lngSize
strConve = Space$(lngSize)
For i = 0 To lngSize - 1 Step 1
Mid$(strConve, i + 1, 1) = Chr$(bytArray(i))
If (i / 100 = i \ 100) Then
.Value = i
Label5.Caption = Format(i, "#,###,###") & "/" _
& Format(lngSize, "#,###,###") & "[" _
& Format(Int((i / lngSize) * 100), "@@@") & "%]"
DoEvents
End If
Next i
End With
Debug.Print strConve
'txtHTTPData.Text = strConve
それと切れてしまう例は(例としてHTML)、以下が一行に表示されて切れます。(貼り付けたら勝手に改行されました。)
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=Shift_JIS">
<meta name="robots" content="noarchive">
<meta name="description" content="
訂正
問題なのですが
問題ないと思うのですが
文字列バッファクラスです。
使い方は----より下を"StringBuffer.cls"として保存し、
プロジェクトに追加してください。あとは「使用例)」を参照してください。
バグがあったらごめんなさい。
---------------------------------------------
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "StringBuffer"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
' @(s)
' 文字列バッファクラス
' 使用例)
'| Dim sb As StringBuffer
'| Set sb = New StringBuffer
'| Call sb.Append("abcde")
'| Call sb.Append("123")
'| Call MsgBox(sb.ToString)
'
Option Explicit
Private Const DEF_BUF_SIZE As Long = 128 '' デフォルトのバッファサイズ
Private m_Text As String '' 文字列
Private m_Length As Long '' 文字列長
Private m_CapacityIncrement As Long '' バッファ増加量
Private m_Capacity As Long '' バッファ容量
' @(e)
'
' 機能 : コンストラクタ
'
Private Sub Class_Initialize()
Call Init(DEF_BUF_SIZE) '' 初期化処理呼び出し
End Sub
' @(f)
'
' 機能 : 初期化
'
' 引き数 : ARG1 - [in ]文字列の長さ
'
' 機能説明 :
'
' 備考 :
'
Public Sub Init(ByVal lInitialCapacity As Long)
m_Length = 0 '' 文字列長初期化
m_CapacityIncrement = lInitialCapacity '' 同時に確保する文字数初期化
If m_CapacityIncrement < 1 Then '' 1未満ならデフォルト値設定
m_CapacityIncrement = DEF_BUF_SIZE
End If
m_Text = String$(m_CapacityIncrement, 0) '' 文字列初期化
m_Capacity = m_CapacityIncrement '' バッファ長初期化
End Sub
' @(f)
'
' 機能 : 文字列追加
'
' 引き数 : ARG1 - [in ]追加する文字列
'
' 機能説明 : 文字列バッファに文字列を追加する
'
Public Sub Append(ByRef sAddStr As String)
Dim lAddStrLen As Long ' 追加する文字列長
lAddStrLen = Len(sAddStr)
'' 現在確保しているバッファ長で足りない?
If m_Capacity < (m_Length + lAddStrLen) Then
''' バッファ確保
m_CapacityIncrement = m_CapacityIncrement * 2
m_Text = m_Text & String$(m_CapacityIncrement, 0)
m_Capacity = m_Capacity + m_CapacityIncrement
End If
'' 文字列追加
Mid$(m_Text, m_Length + 1, lAddStrLen) = sAddStr
'' 文字列長設定
m_Length = m_Length + lAddStrLen
End Sub
' @(f)
'
' 機能 : 文字列取得
'
' 返り値 : 文字列
'
Public Property Get Text() As String
Text = Left$(m_Text, m_Length)
End Property
' @(f)
'
' 機能 : 文字列設定
'
' 引き数 : ARG1 - 設定する文字列
'
Public Property Let Text(ByRef sNewText As String)
m_Text = sNewText
m_Length = Len(m_Text)
m_Capacity = m_Length
End Property
' @(f)
'
' 機能 : 文字列クリア
'
Public Sub Clear()
m_Text = ""
m_Length = 0
m_Capacity = 0
End Sub
' @(f)
'
' 機能 : 文字列取得
'
' 返り値 : 文字列
'
Public Property Get ToString() As String
ToString = Left$(m_Text, m_Length)
End Property
' @(f)
'
' 機能 : 文字列バッファの容量取得
'
' 返り値 : 文字列バッファの現在の容量
'
Public Property Get Capacity() As Long
Capacity = m_Capacity
End Property
ありがとうございました!!
皆様のおかげで見違えるほど高速になりました!
VBでも、作り方によってぜんぜん違うんですね。
これからも勉強していきたいと思います。
ありがとうございました。