Parsing a long string into increments of 30 characters

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hi there,

I have a large string I need to parse into increments of 30 characters, each set to print on a separate line. The below code produces unfavorable results:

For intStart = 1 to Len(strOriginal) by 30
strPrint = Mid$(strOriginal, intStart, intStart + 29)
'print result here
Next intStart

It's parsing out the first line correctly, but the second line has 60, then 90, 120, etc. and each line borrows something willy nilly from the previous line. It's driving me crazy. If anybody has any thoughts, I'd sure appreciate some direction. Thanks in advance.
 
Meldrape said:
Hi there,

I have a large string I need to parse into increments of 30
characters, each set to print on a separate line. The below code
produces unfavorable results:

For intStart = 1 to Len(strOriginal) by 30
strPrint = Mid$(strOriginal, intStart, intStart + 29)
'print result here
Next intStart

It's parsing out the first line correctly, but the second line has
60, then 90, 120, etc. and each line borrows something willy nilly
from the previous line. It's driving me crazy. If anybody has any
thoughts, I'd sure appreciate some direction. Thanks in advance.

How about:

For intStart = 1 To Len(strOriginal) Step 30
strPrint = Mid$(strOriginal, intStart, 30)
'print result here
Next intStart

Though actually, I'd use a Long for the "Start" variable rather than an
Integer, just in case you have a string longer than 32,767 bytes.
 
How about (untested):

Do While Len(strInput) > 0
strPrint = Left(strInput, 30)
Debug.Print strPrint
strInput = Mid(strInput,31)
Loop

--
HTH
Van T. Dinh
MVP (Access)



Meldrape said:
Hi there,

I have a large string I need to parse into increments of 30 characters,
each set to print on a separate line. The below code produces unfavorable
results:
For intStart = 1 to Len(strOriginal) by 30
strPrint = Mid$(strOriginal, intStart, intStart + 29)
'print result here
Next intStart

It's parsing out the first line correctly, but the second line has 60,
then 90, 120, etc. and each line borrows something willy nilly from the
previous line. It's driving me crazy. If anybody has any thoughts, I'd
sure appreciate some direction. Thanks in advance.
 
Van T. Dinh said:
How about (untested):

Do While Len(strInput) > 0
strPrint = Left(strInput, 30)
Debug.Print strPrint
strInput = Mid(strInput,31)
Loop

Not that it's likely to make any practical difference, Van, but I don't
like that approach because of the relative inefficiency involved in
unnecessarily modifying strInput for each substring.
 
I am just being lazy...

I am not sure whether chopping off and always take the left 30 is more or
less efficient than counting 30,000,001 then 30,000,031 then 30,000, 061
..... and VBA doesn't have to count the number of characters at the beginning
or to keep track of the index for the loop.
 
Van T. Dinh said:
I am just being lazy...

I am not sure whether chopping off and always take the left 30 is
more or less efficient than counting 30,000,001 then 30,000,031 then
30,000, 061 .... and VBA doesn't have to count the number of
characters at the beginning or to keep track of the index for the
loop.

In my experience, string operations are much more expensive than simple
arithmetic ones, especially loop-index increments that can be handled in
hardware registers. But I'm just being lazy (;-) -- the only way to
make meaningful claims about efficiency is to do performance tests. I'm
off to do some benchmarks ...
 
Dirk Goldgar said:
I'm off to do some benchmarks ...

.... And here they are. Module code was this (wrapped by newsreader):

'----- start of code -----
Option Compare Database
Option Explicit

Private Type LARGE_INTEGER
lowpart As Long
highpart As Long
End Type

Private Declare Function QueryPerformanceCounter Lib "kernel32"
(lpPerformanceCount As LARGE_INTEGER) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32"
(lpFrequency As LARGE_INTEGER) As Long

Private Function LargeToDec(arg As LARGE_INTEGER) As Variant
LargeToDec = arg.lowpart + 2 * CDec(arg.highpart) * 2 ^ 31
End Function

Sub subDirksVersion(ByRef strInput As String)

Dim strPrint As String
Dim lngStart As Long

For lngStart = 1 To Len(strInput) Step 30
strPrint = Mid$(strInput, lngStart, 30)
Next lngStart

End Sub

Sub subVansVersion(ByRef strInput As String)

Dim strPrint As String

Do While Len(strInput) > 0
strPrint = Left(strInput, 30)
strInput = Mid(strInput, 31)
Loop

End Sub

Sub BenchStringSplitter(Optional NTIMES As Long = 1)

Dim result As Variant
Dim freq As LARGE_INTEGER
Dim starting As LARGE_INTEGER
Dim ending As LARGE_INTEGER
Dim dfreq As Variant
Dim lngCount As Long
Dim strOriginal As String
Dim strWork As String

QueryPerformanceFrequency freq
dfreq = LargeToDec(freq)

strOriginal = String(32767, "A")

' Make sure both functions have been loaded.
strWork = strOriginal
subDirksVersion strWork
strWork = strOriginal
subVansVersion strWork

' Test with long string.
strOriginal = String(32767, "A")

QueryPerformanceCounter starting
For lngCount = 1 To NTIMES
strWork = strOriginal
subVansVersion strWork
Next lngCount
QueryPerformanceCounter ending
Debug.Print "Van's version, string length = " & _
Len(strOriginal) & ": ", _
(LargeToDec(ending) - LargeToDec(starting)) / dfreq

QueryPerformanceCounter starting
For lngCount = 1 To NTIMES
strWork = strOriginal
subDirksVersion strWork
Next lngCount
QueryPerformanceCounter ending
Debug.Print "Dirk's version, string length = " & _
Len(strOriginal) & ": ", _
(LargeToDec(ending) - LargeToDec(starting)) / dfreq

' Test with short string.
strOriginal = String(90, "A")

QueryPerformanceCounter starting
For lngCount = 1 To NTIMES
strWork = strOriginal
subVansVersion strWork
Next lngCount
QueryPerformanceCounter ending
Debug.Print "Van's version, string length = " & _
Len(strOriginal) & ": ", _
(LargeToDec(ending) - LargeToDec(starting)) / dfreq

QueryPerformanceCounter starting
For lngCount = 1 To NTIMES
strWork = strOriginal
subDirksVersion strWork
Next lngCount
QueryPerformanceCounter ending
Debug.Print "Dirk's version, string length = " & _
Len(strOriginal) & ": ", _
(LargeToDec(ending) - LargeToDec(starting)) / dfreq

' Test with zero-length string.
strOriginal = vbNullString

QueryPerformanceCounter starting
For lngCount = 1 To NTIMES
strWork = strOriginal
subVansVersion strWork
Next lngCount
QueryPerformanceCounter ending
Debug.Print "Van's version, string length = " & _
Len(strOriginal) & ": ", _
(LargeToDec(ending) - LargeToDec(starting)) / dfreq

QueryPerformanceCounter starting
For lngCount = 1 To NTIMES
strWork = strOriginal
subDirksVersion strWork
Next lngCount
QueryPerformanceCounter ending
Debug.Print "Dirk's version, string length = " & _
Len(strOriginal) & ": ", _
(LargeToDec(ending) - LargeToDec(starting)) / dfreq

End Sub
'----- end of code -----

And the results of executing with loop count of 100:

----- copied from the Immediate Window -----
benchstringsplitter 100
Van's version, string length = 32767:
1.9502730095584774042510989525
Dirk's version, string length = 32767:
0.0465799424228498314729944728
Van's version, string length = 90:
0.0003774222701488597014425018
Dirk's version, string length = 90:
0.0001877333571724897996812444
Van's version, string length = 0: 0.000049726990441522595748901
Dirk's version, string length = 0: 0.00005280000670476275616035
----- end copy -----

Obviously it makes a difference how many times you go through the loop.
Also, I had to leave a string assignment in the loop for both functions,
because subVansVersion is destructive of the original argument string.
 
Back
Top