Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations wOOdy-Soft on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Replace function 5

Status
Not open for further replies.

CCLINT

Programmer
Feb 22, 2002
3,802
DE

I guess I'm a little exhasted from testing. I cannot seem to figure something out.
I am trying to find the fastest method for finding and replacing text using VB methods.

I am using the below ReplaceX function which is a (partial)substitue for the VB Replace function.

Now, the ReplaceX function, when using binary comparision, seems to be about 75% faster!! And, with compiled code that much more again.

This is probably because the VB Replace function uses SafeArray, which calls are slow, and, there isn't the extra overhead in the ReplaceX function as there is with the Replace function, which has two additional optional parameters.

So, if you need a fast Replace function with-in VB, using binary comparison, this seems to be a good choice.

OK, the problem is when using Text comparison. The ReplaceX function seems to be 70% slower than the VB Replace function.
I guess this is due to the VB InStr function being used.

********************************************************
Now to my requests:

1. Would some of you be willing to test this and report what results you come up with?

2. Any suggestions to improve this?

3. Does anyone have a faster method for Text comparison, or at all?


Public Function ReplaceX(Expression As String, ByVal ReplaceWhat As String, ByVal ReplaceWith As String, _
Optional CompareMethod As VbCompareMethod = vbBinaryCompare) As String
Dim lPos As Long
Dim lStrLen As Long

lPos = 1
lStrLen = Len(ReplaceWith)

Do
lPos = InStr(lPos, Expression, ReplaceWhat, CompareMethod)

If lPos > 0 Then
Expression = Left$(Expression, lPos - 1) + ReplaceWith + Mid$(Expression, lPos + Len(ReplaceWhat))
lPos = lPos + lStrLen
End If
Loop Until lPos = 0

ReplaceX = Expression

End Function

Thankyou and best regards to all! *******************************************************
General remarks:
If this post contains any suggestions for the use or distribution of code, components or files of any sort, it is still your responsibility to assure that you have the proper license and distribution rights to do so!
 
Also, here is the method I used for timing:

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

Public Sub StartTest()
Dim loopX As Long
Dim StartTicks As Currency
Dim StopTicks As Currency
Dim Frequency As Currency

QueryPerformanceFrequency Frequency
QueryPerformanceCounter StartTicks

For loopX = 1 To 100000

'Test with binary compare:
ReplaceX "123AbC456", "AB", "XX", vbTextCompare
'Replace "123AbC456", "AB", "XX", , , vbTextCompare

'Test with Text compare:
'ReplaceX "123AbC456", "AB", "XX", vbTextCompare
'Replace "123AbC456", "AB", "XX", , , vbTextCompare

Next loopX

QueryPerformanceCounter StopTicks

Debug.Print (StopTicks - StartTicks) / Frequency

End Sub *******************************************************
General remarks:
If this post contains any suggestions for the use or distribution of code, components or files of any sort, it is still your responsibility to assure that you have the proper license and distribution rights to do so!
 
Yes, CCLINT, - I have a general timing test engine (that you've shown in other threads). I'll run the tests with the intrinsic Replace, your ReplaceX, and I'll add in the RegExp Replace, and an Idea or 2 that I have. I'll post the resutls, you can expect, in about 3 hours. (I have a small work related project that I need to attend to first. Its a shame that real work has to get in the way of progress.) Good Luck
--------------
As a circle of light increases so does the circumference of darkness around it. - Albert Einstein
 
I get similar results in my test rig. As a fan of Regular Expressions, I've tested those as well. With a string of the length given here, the RE solution is about twice as fast as ReplaceX in binary comparison mode. However, I suggest that you try increasing the string length, and seeing how it affects the results (eg, at 64000, Replace in Text Comparison mode is without the fastest by a long way)
 
Great CajunCenturion!

Regular Expressions seems to be much faster than ReplaceX or VB Replace, with binary and text compare.

One thing I forgot to mention: when I tested ReplaceX, I didn't use an optional argument for the text comparison. It was left as binary and the function only used 3 arguments.

I then did the test with text comparison and also, this time, with the function only having 3 arguments, ReplaceX beats Replace! If this is correct, then using 2 seperate replaceX functions will beat the VB Replace. That would then show what type of overhead is relly caused with just on additional optional argument.

And the RegExp Replace beats them all by far!

Yes strongm, I can see why you are a fan of RE.
So, if I would have used RE from the start, I would have been on the right track from the start.

Thanks.

Will be interested in CajunCenturion's results as well

(CajunCenturion: please test ReplaceX with-out the 4th argument as well - remove it completely) *******************************************************
General remarks:
If this post contains any suggestions for the use or distribution of code, components or files of any sort, it is still your responsibility to assure that you have the proper license and distribution rights to do so!
 
Ok, I also tested it with a long string and alot of matches. I guess I loose in this case against the VB Replace. For short strings it is different.


CajunCenturion, you do not need to bother anymore with the testing. I'm on the right track now.

I didn't even think about using RE instead (mind block/old habits, I don't know).

*******************************************************
General remarks:
If this post contains any suggestions for the use or distribution of code, components or files of any sort, it is still your responsibility to assure that you have the proper license and distribution rights to do so!
 
Ok, here are the results from my testing

With respect to the intrinsic Replace function, regardless of the string size, a 56K size string, and a string of 15 chars, the Binary Replace was approx half the time of the Text Replace.

I also check several flavors of your Replace routine, and the fastest was to use the following - which is actually Sub with all parameters passed by reference, thus not incurring the overhead of the function return value handling. With respect to three or four parameters, there was a measurable difference, but it was quite small, almost to the point of being insignificant. Nevertheless, the fastest flavor of your routine was the following:

Public Sub ReplaceX(Expression As String, ReplaceWhat As String, ReplaceWith As String)

Dim lPos As Long
Dim lStrLen As Long

lPos = 1
lStrLen = Len(ReplaceWith)
Do
lPos = InStr(lPos, Expression, ReplaceWhat, vbBinaryCompare)
If lPos > 0 Then
Expression = Left$(Expression, lPos - 1) + ReplaceWith + Mid$(Expression, lPos + Len(ReplaceWhat))
lPos = lPos + lStrLen
End If
Loop Until lPos = 0

End Sub

For the final test, I compared the different methods. I used three different Regular Expressions - 1 with a global object, and the other two with local objects. The two local object tests were to see if there was a difference between this (Explicit):

Dim lRegExp As RegExp

Set lRegExp = New RegExp
lRegExp.Pattern = ReplaceWhat
lRegExp.Global = True
Expression = lRegExp.Replace(Expression, ReplaceWith)
Set lRegExp = Nothing

and this (Implicit)

Dim lRegExp As New RegExp

lRegExp.Pattern = ReplaceWhat
lRegExp.Global = True
Expression = lRegExp.Replace(Expression, ReplaceWith)

For a 15 character length string with 1 replacement:

Instrinsic Replace: Ave Time = .002012
CCLINT ReplaceX SuB: .001137
RegExp Local Explicit: .050117
RegExp Local Implicit: .049796
RegExp Global: .005905

For this case, your CCLINT's routine was the winner, followed by the intrinsic Replace, then the Global RegExp object. Clearly, if you're going to use the RE for the replace, make it Global.

Now with a String 56K chars long, requiring 2400 replacements, here's how it shaped up:

Instrinsic Replace: Ave Time = .183437
CCLINT ReplaceX SuB: 44.896991
RegExp Local Explicit: .088520
RegExp Local Implicit: .088335
RegExp Global: .081693

In this case, the global RegExp is the winner, followed closed by the other two RegExp options. The RegExp is over twice as fast as the instrinsic Replace function when dealing with strings of this size and number of replacements.
Good Luck
--------------
As a circle of light increases so does the circumference of darkness around it. - Albert Einstein
 
Thanks CajunCenturion!
So it must be the lack of overhead and SafeArrays that makes ReplaceX work faster on short strings, but once the string is too long, or has too many replacements, the methods inside of ReplaceX slow it down considerably.
I had also passed the arguments by ref and by val. Ref should, but I didn't find a real difference either.

So, I guess if it is a short string, and there are alot of short strings to do replacing on, and speed is needed, then use ReplaceX.
But, really, who will need this speed on short strings to this extent (we are talking about thousands of loops in testing - but with one or two replacements is there really a need to resort to another replace function?

Thanks again! *******************************************************
General remarks:
If this post contains any suggestions for the use or distribution of code, components or files of any sort, it is still your responsibility to assure that you have the proper license and distribution rights to do so!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top