Solved

Reading characters in a string.

Posted on 2001-07-10
18
241 Views
Last Modified: 2007-12-19
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.

0
Comment
Question by:brandonb
  • 6
  • 5
  • 4
  • +2
18 Comments
 
LVL 3

Expert Comment

by:jrspano
ID: 6270593
post the code.
0
 
LVL 2

Expert Comment

by:exelrud
ID: 6270620
Is this a function or do you create another process to handle the uncompression or do it on the idle time ?
0
 
LVL 1

Author Comment

by:brandonb
ID: 6270646
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(TalkInputString 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
0
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 2

Expert Comment

by:exelrud
ID: 6270683
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)
0
 
LVL 2

Expert Comment

by:exelrud
ID: 6270685
Ooops.
Change the for into a While.
0
 
LVL 38

Expert Comment

by:PaulHews
ID: 6270835
This kind of manipulation would be a lot faster in a byte array.
0
 
LVL 1

Author Comment

by:brandonb
ID: 6270946
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?
0
 
LVL 2

Accepted Solution

by:
exelrud earned 100 total points
ID: 6270974
Maybe so, maybe not.
The debug environment may act in a different way then the compiled code.
It should behave the same but "should" and "does" and 2 different words...
0
 
LVL 38

Expert Comment

by:PaulHews
ID: 6271022
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(TalkInputString 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(intCount) = 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(intCount) = chSpace
'                       Uncompress_String = Uncompress_String + String(Cntr, " ")
                   Else
                        bytUncompressedString(intCount) = 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(intCount) = Char
'               Uncompress_String = Uncompress_String + Char
           End If
       End If
       
   Next X
   Uncompress_String = StrConv(bytUncompressedString, vbUnicode)   'Convert bytes back to string
   
End Function
0
 
LVL 38

Expert Comment

by:PaulHews
ID: 6271024
Commented out your code where mine was different...

This should perform significantly faster, especially if the strings are long.
0
 
LVL 38

Expert Comment

by:PaulHews
ID: 6271029
Found one bug already:

If Char > 123 Then
          NextChar = bytInputString(i) 'Mid$(TalkInputString, X + 1, 1)
      End If
0
 
LVL 1

Author Comment

by:brandonb
ID: 6271088
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.
0
 
LVL 14

Expert Comment

by:wsh2
ID: 6271308
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(TalkInputString 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 ----->
0
 
LVL 1

Author Comment

by:brandonb
ID: 6274415
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
0
 
LVL 14

Expert Comment

by:wsh2
ID: 6276449
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
0
 
LVL 1

Author Comment

by:brandonb
ID: 6294921
Thanks for help everyone.
0
 
LVL 38

Expert Comment

by:PaulHews
ID: 6294933
Ah.  Did you intentionally choose that answer, or was it a mistake.
0
 
LVL 1

Author Comment

by:brandonb
ID: 6294987
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.
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

There are many ways to remove duplicate entries in an SQL or Access database. Most make you temporarily insert an ID field, make a temp table and copy data back and forth, and/or are slow. Here is an easy way in VB6 using ADO to remove duplicate row…
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

840 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question