brandonb
asked on
Reading characters in a string.
I have a function that takes a compressed string, uncompresses it, and returns the uncompressed string. The compression is very simple. When 3 or more consecutive spaces or zeroes are encountered, they are removed and replaced with a flag (ASCII 126 for zeroes and ASCII 127 for spaces) and the binary number of spaces or zeroes. All of this works properly.
My problem is that when I create an EXE, the program takes 2 to 3 times longer to uncompress the string than just running the program through the VB IDE. Both are running the exact same code.
Any ideas on what the problem could be? I can post the code if it will help.
My problem is that when I create an EXE, the program takes 2 to 3 times longer to uncompress the string than just running the program through the VB IDE. Both are running the exact same code.
Any ideas on what the problem could be? I can post the code if it will help.
post the code.
Is this a function or do you create another process to handle the uncompression or do it on the idle time ?
ASKER
Here is the code. One other thing to mention about the compression is that if there are ASCII characters > 123, the compression routine doubles them as a way to let the uncompression routine know that they are truly characters not flags.
This is a function that is called from a .BAS module.
Function Uncompress_String(TalkInpu tString As String)
Dim Char As String
Dim NextChar As String
Dim Cntr As Integer
Uncompress_String = ""
For X = 1 To Len(TalkInputString)
Char = Mid$(TalkInputString, X, 1)
If Char > Chr$(123) Then
NextChar = Mid$(TalkInputString, X + 1, 1)
End If
If Char > Chr$(123) And Char = NextChar Then
Uncompress_String = Uncompress_String + Char
Else
If Char = Chr$(126) Or Char = Chr$(127) Then
Cntr = Asc(NextChar)
If Char = Chr$(127) Then
Uncompress_String = Uncompress_String + String(Cntr, " ")
Else
Uncompress_String = Uncompress_String + String(Cntr, "0")
End If
X = X + 1
Else
Uncompress_String = Uncompress_String + Char
End If
End If
Next X
End Function
This is a function that is called from a .BAS module.
Function Uncompress_String(TalkInpu
Dim Char As String
Dim NextChar As String
Dim Cntr As Integer
Uncompress_String = ""
For X = 1 To Len(TalkInputString)
Char = Mid$(TalkInputString, X, 1)
If Char > Chr$(123) Then
NextChar = Mid$(TalkInputString, X + 1, 1)
End If
If Char > Chr$(123) And Char = NextChar Then
Uncompress_String = Uncompress_String + Char
Else
If Char = Chr$(126) Or Char = Chr$(127) Then
Cntr = Asc(NextChar)
If Char = Chr$(127) Then
Uncompress_String = Uncompress_String + String(Cntr, " ")
Else
Uncompress_String = Uncompress_String + String(Cntr, "0")
End If
X = X + 1
Else
Uncompress_String = Uncompress_String + Char
End If
End If
Next X
End Function
I do not like using X = X + 1 inside a for X
change the for X for a while just to be sure.
The compiler otimizations may conflict with what you're trying to do (skip a char)
change the for X for a while just to be sure.
The compiler otimizations may conflict with what you're trying to do (skip a char)
Ooops.
Change the for into a While.
Change the for into a While.
This kind of manipulation would be a lot faster in a byte array.
ASKER
PaulHews,
I haven't ever used a byte array. Could you give me an example? Speed is of the utmost importance. This is a piece of a communications package between a UNIX C program and a VB program. Some of our sites use a 56K lease line. We have experimented with gzip compression, but found this simple compression gives us the best combination of compression and processing time. Anything that would speed up the compression/uncompression would be greatly appreciated.
exelrud,
I understand the concern with adding 1 to X, but would I not have the same problem running the program through the IDE?
I haven't ever used a byte array. Could you give me an example? Speed is of the utmost importance. This is a piece of a communications package between a UNIX C program and a VB program. Some of our sites use a 56K lease line. We have experimented with gzip compression, but found this simple compression gives us the best combination of compression and processing time. Anything that would speed up the compression/uncompression would be greatly appreciated.
exelrud,
I understand the concern with adding 1 to X, but would I not have the same problem running the program through the IDE?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
This is what I mean... I can't really test this, so there may be bugs, but it is the broad idea of what I mean:
Function Uncompress_String(TalkInpu tString As String) As String
Dim Char As Byte
Dim NextChar As Byte
Dim Cntr As Integer
Dim bytInputString() As Byte
Dim bytUncompressedString() As Byte 'Output string
Dim intChunkSize As Integer 'used to allocate memory in 1K blocks (faster)
Dim intCount As Integer 'incremented for each addition to output
'AscII constants
Const chSpace As Byte = 32
Const chZero As Byte = 48
intChunkSize = 1024
bytInputString = StrConv(TalkInputString, vbFromUnicode) 'Convert string to bytes
' Uncompress_String = ""
intCount = 0
For X = 1 To Len(TalkInputString)
Char = bytInputString(i - 1) 'Mid$(TalkInputString, X, 1)
If Char > 123 Then
NextChar = bytInputString(i - 1) 'Mid$(TalkInputString, X + 1, 1)
End If
If Char > 123 And Char = NextChar Then
'This code could go in a sub for readability, but a little faster inline. :)
intCount = intCount + 1
If intCount > intChunkSize Then
intChunkSize = intChunkSize + 1024
ReDim Preserve bytUncompressedString(1 To intChunkSize)
End If
bytUncompressedString(intC ount) = Char
'Uncompress_String = Uncompress_String + Char
Else
If Char = 126 Or Char = 127 Then
Cntr = NextChar
intCount = intCount + 1
If intCount > intChunkSize Then
intChunkSize = intChunkSize + 1024
ReDim Preserve bytUncompressedString(1 To intChunkSize)
End If
If Char = 127 Then
bytUncompressedString(intC ount) = chSpace
' Uncompress_String = Uncompress_String + String(Cntr, " ")
Else
bytUncompressedString(intC ount) = chZero
' Uncompress_String = Uncompress_String + String(Cntr, "0")
End If
X = X + 1
Else
intCount = intCount + 1
If intCount > intChunkSize Then
intChunkSize = intChunkSize + 1024
ReDim Preserve bytUncompressedString(1 To intChunkSize)
End If
bytUncompressedString(intC ount) = Char
' Uncompress_String = Uncompress_String + Char
End If
End If
Next X
Uncompress_String = StrConv(bytUncompressedStr ing, vbUnicode) 'Convert bytes back to string
End Function
Function Uncompress_String(TalkInpu
Dim Char As Byte
Dim NextChar As Byte
Dim Cntr As Integer
Dim bytInputString() As Byte
Dim bytUncompressedString() As Byte 'Output string
Dim intChunkSize As Integer 'used to allocate memory in 1K blocks (faster)
Dim intCount As Integer 'incremented for each addition to output
'AscII constants
Const chSpace As Byte = 32
Const chZero As Byte = 48
intChunkSize = 1024
bytInputString = StrConv(TalkInputString, vbFromUnicode) 'Convert string to bytes
' Uncompress_String = ""
intCount = 0
For X = 1 To Len(TalkInputString)
Char = bytInputString(i - 1) 'Mid$(TalkInputString, X, 1)
If Char > 123 Then
NextChar = bytInputString(i - 1) 'Mid$(TalkInputString, X + 1, 1)
End If
If Char > 123 And Char = NextChar Then
'This code could go in a sub for readability, but a little faster inline. :)
intCount = intCount + 1
If intCount > intChunkSize Then
intChunkSize = intChunkSize + 1024
ReDim Preserve bytUncompressedString(1 To intChunkSize)
End If
bytUncompressedString(intC
'Uncompress_String = Uncompress_String + Char
Else
If Char = 126 Or Char = 127 Then
Cntr = NextChar
intCount = intCount + 1
If intCount > intChunkSize Then
intChunkSize = intChunkSize + 1024
ReDim Preserve bytUncompressedString(1 To intChunkSize)
End If
If Char = 127 Then
bytUncompressedString(intC
' Uncompress_String = Uncompress_String + String(Cntr, " ")
Else
bytUncompressedString(intC
' Uncompress_String = Uncompress_String + String(Cntr, "0")
End If
X = X + 1
Else
intCount = intCount + 1
If intCount > intChunkSize Then
intChunkSize = intChunkSize + 1024
ReDim Preserve bytUncompressedString(1 To intChunkSize)
End If
bytUncompressedString(intC
' Uncompress_String = Uncompress_String + Char
End If
End If
Next X
Uncompress_String = StrConv(bytUncompressedStr
End Function
Commented out your code where mine was different...
This should perform significantly faster, especially if the strings are long.
This should perform significantly faster, especially if the strings are long.
Found one bug already:
If Char > 123 Then
NextChar = bytInputString(i) 'Mid$(TalkInputString, X + 1, 1)
End If
If Char > 123 Then
NextChar = bytInputString(i) 'Mid$(TalkInputString, X + 1, 1)
End If
ASKER
I'm going to give both of you points for your help. exelrud seems to have solved my problem and I'm just beginning to test PaulHews code.
Built for speed.. <smile>
========================== ========== ========== =======
1. Start a New Standard.Exe Project.
2. Copy/Paste the following into the Form1 code window.
3. Press F8 to Run. The contents of strWork will appear in a MsgBox.
<----- Code Begin ----->
Option Explicit
Private Sub Form_Load()
Dim strWork As String
strWork = "a" & Chr(127) & Chr(12) & "b"
MsgBox Uncompress_String(strWork)
End Sub
Function Uncompress_String(TalkInpu tString As String)
Dim bytGet() As Byte: ReDim bytGet(Len(TalkInputString ) * 1)
Dim lngGet As Long: lngGet = 0
Dim bytPut() As Byte: ReDim bytPut(Len(TalkInputString ) * 2) ' Estimate
Dim lngPut As Long: lngPut = 0
Dim lngX As Long
bytGet() = StrConv(TalkInputString & ":", vbFromUnicode)
For lngGet = LBound(bytGet) To UBound(bytGet) - 1
If (bytGet(lngGet) = 126 And bytGet(lngGet + 1) <> 126) _
Or (bytGet(lngGet) = 127 And bytGet(lngGet + 1) <> 127) _
Then
For lngX = 1 To bytGet(lngGet + 1)
Select Case bytGet(lngGet)
Case 126
bytPut(lngPut) = Asc(" ")
Case 127
bytPut(lngPut) = Asc("0")
End Select
lngPut = lngPut + 1
If lngPut >= UBound(bytPut) Then
ReDim Preserve bytPut(lngPut)
End If
Next lngX
lngGet = lngGet + 1
Else
If bytGet(lngGet) > 123 And bytGet(lngGet) = bytGet(lngGet + 1) Then
lngGet = lngGet + 1
End If
bytPut(lngPut) = bytGet(lngGet)
lngPut = lngPut + 1
If lngPut >= UBound(bytPut) Then
ReDim Preserve bytPut(lngPut)
End If
End If
Next lngGet
ReDim Preserve bytPut(lngPut - 1)
Uncompress_String = StrConv(bytPut(), vbUnicode)
End Function
<----- Code End ----->
==========================
1. Start a New Standard.Exe Project.
2. Copy/Paste the following into the Form1 code window.
3. Press F8 to Run. The contents of strWork will appear in a MsgBox.
<----- Code Begin ----->
Option Explicit
Private Sub Form_Load()
Dim strWork As String
strWork = "a" & Chr(127) & Chr(12) & "b"
MsgBox Uncompress_String(strWork)
End Sub
Function Uncompress_String(TalkInpu
Dim bytGet() As Byte: ReDim bytGet(Len(TalkInputString
Dim lngGet As Long: lngGet = 0
Dim bytPut() As Byte: ReDim bytPut(Len(TalkInputString
Dim lngPut As Long: lngPut = 0
Dim lngX As Long
bytGet() = StrConv(TalkInputString & ":", vbFromUnicode)
For lngGet = LBound(bytGet) To UBound(bytGet) - 1
If (bytGet(lngGet) = 126 And bytGet(lngGet + 1) <> 126) _
Or (bytGet(lngGet) = 127 And bytGet(lngGet + 1) <> 127) _
Then
For lngX = 1 To bytGet(lngGet + 1)
Select Case bytGet(lngGet)
Case 126
bytPut(lngPut) = Asc(" ")
Case 127
bytPut(lngPut) = Asc("0")
End Select
lngPut = lngPut + 1
If lngPut >= UBound(bytPut) Then
ReDim Preserve bytPut(lngPut)
End If
Next lngX
lngGet = lngGet + 1
Else
If bytGet(lngGet) > 123 And bytGet(lngGet) = bytGet(lngGet + 1) Then
lngGet = lngGet + 1
End If
bytPut(lngPut) = bytGet(lngGet)
lngPut = lngPut + 1
If lngPut >= UBound(bytPut) Then
ReDim Preserve bytPut(lngPut)
End If
End If
Next lngGet
ReDim Preserve bytPut(lngPut - 1)
Uncompress_String = StrConv(bytPut(), vbUnicode)
End Function
<----- Code End ----->
ASKER
wsh2,
Your code works great except if I change anything after pasting the code in my program. If I add some blank lines or realign the beginning of each line with the program, I receive the following error when I try to run the program. Sometimes, when VB restarts, the error doesn't occur again, but other times it still does. Any ideas?
The instruction at "0x0facb9ac" referenced memory at "0x00000000". The memory could not be "read".
Click on OK to terminate the program
Click on CANCEL to debug the program
Your code works great except if I change anything after pasting the code in my program. If I add some blank lines or realign the beginning of each line with the program, I receive the following error when I try to run the program. Sometimes, when VB restarts, the error doesn't occur again, but other times it still does. Any ideas?
The instruction at "0x0facb9ac" referenced memory at "0x00000000". The memory could not be "read".
Click on OK to terminate the program
Click on CANCEL to debug the program
brandonb..
It sounds like your copy of Visual Basic is corrupt.. <sigh>. You may want to consider reinstalling it and applying VB6 SP5 which you can get at this URL address:
http://msdn.microsoft.com/vstudio/sp/vs6sp5
It sounds like your copy of Visual Basic is corrupt.. <sigh>. You may want to consider reinstalling it and applying VB6 SP5 which you can get at this URL address:
http://msdn.microsoft.com/vstudio/sp/vs6sp5
ASKER
Thanks for help everyone.
Ah. Did you intentionally choose that answer, or was it a mistake.
ASKER
Intentionally. exelrud's suggestion solved my original problem.
Check the question list. There should be a "question" just for you for your help with the byte array.
BTW, the error I was receiving has something to do with the code not VB being corrupt. I haven't had the time to narrow it down, but I modified PaulHews code and it works wonderfully.
Check the question list. There should be a "question" just for you for your help with the byte array.
BTW, the error I was receiving has something to do with the code not VB being corrupt. I haven't had the time to narrow it down, but I modified PaulHews code and it works wonderfully.