Thread Rating:
  • 1 Vote(s) - 4 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Fast replace$() function
#8
(04-18-2025, 09:08 PM)mdijkens Wrote: You are absolutely right.
For performance sake, I just reserve 'enough' space for the specific usecase at hand.
If you have a case where the replace could make the resulting string more then 2x the size, you'd have to increase it.
making it dynamic with inline resizing would make it (a lot) slower; In my scenario this is run millions of times so I'd rather reserve multiple GB for _mem just to be sure (memory enough to spare)
$Checking:Off would definitely help also

To compare, here's an auto-resizing version so you can see the speed hit is fairly minimal.

Code: (Select All)
$Console:Only
Const SIZE = 200000000
Randomize Timer
Dim As Double t(20), t1(20), d(20)


Print "Original", , "Steve", , "Diff"
For i = 1 To 20
txt$ = String$(SIZE, 0)
For p& = 1 To SIZE
Asc(txt$, p&) = 32 + p& Mod 96
Next p&

t1# = Timer(.001#)
result$ = mreplace$(txt$, "A", "Hello")
t2# = Timer(.001#)
result$ = SteveReplace$(txt$, "A", "Hello")
t3# = Timer(0.001#)
t(i) = t2# - t1#
t1(i) = t3# - t2#
d(i) = t1(i) - t(i)
total# = total# + t(i)
total1# = total1# + t1(i)
tdiff# = tdiff# + d(i)
Print Using "##.### seconds"; t(i),
Print Using "##.### seconds"; t1(i),
Print " ",
Print Using "(##.### diff)"; d(i)
Next
Print
Print
Print Using "##.### seconds"; total#,
Print Using "##.### seconds"; total1#,
Print " ",
Print Using "(##.### diff)"; tdiff#


End


Function replace$ (content$, from$, to$)
content2$ = content$
flen& = Len(from$): tlen& = Len(to$)
p& = InStr(content2$, from$)
If flen& = Len(to$) Then
Do While p& > 0
Mid$(content2$, p&, flen&) = to$
p& = InStr(p& + tlen&, content2$, from$)
Loop
Else
Do While p& > 0
content2$ = Left$(content2$, p& - 1) + to$ + Mid$(content2$, p& + flen&)
p& = InStr(p& + tlen&, content2$, from$)
Loop
End If
replace$ = content2$
End Function

Function mreplace$ (content$, from$, to$)
Dim mp As Long, pp As Long, m As _MEM
m = _MemNew(Len(content$) * 2): mp = 0: pp = 1
flen& = Len(from$): tlen& = Len(to$)
p& = InStr(content$, from$)
Do While p& > 0
_MemPut m, m.OFFSET + mp, Mid$(content$, pp, p& - pp): mp = mp + p& - pp
_MemPut m, m.OFFSET + mp, to$: mp = mp + tlen&: pp = p& + flen&
p& = InStr(p& + flen&, content$, from$)
Loop
_MemPut m, m.OFFSET + mp, Mid$(content$, pp): mp = mp + Len(Mid$(content$, pp))
content2$ = String$(mp, 0): _MemGet m, m.OFFSET, content2$: _MemFree m
mreplace$ = content2$
End Function

Function String.Count& (content$, search$)
If search$ = "" Then Exit Function
p& = InStr(content$, search$)
l& = Len(search$)
Do While p& > 0
count = count + 1
p& = InStr(p& + l&, content$, search$)
Loop
String.Count = count
End Function

$Checking:Off
Function SteveReplace$ (content$, from$, to$)
Dim As Long mp, pp, found
Dim m As _MEM
found = String.Count(content$, from$)
flen& = Len(from$): tlen& = Len(to$)

m = _MemNew(Len(content$) + (tlen& - flen&) * found): mp = 0: pp = 1
p& = InStr(content$, from$)
Do While p& > 0
_MemPut m, m.OFFSET + mp, Mid$(content$, pp, p& - pp): mp = mp + p& - pp
_MemPut m, m.OFFSET + mp, to$: mp = mp + tlen&: pp = p& + flen&
p& = InStr(p& + flen&, content$, from$)
Loop
_MemPut m, m.OFFSET + mp, Mid$(content$, pp): mp = mp + Len(Mid$(content$, pp))
content2$ = String$(mp, 0): _MemGet m, m.OFFSET, content2$: _MemFree m
SteveReplace$ = content2$
End Function
$Checking:On

This runs replace on 200MB strings, and does it 20 times for us. It totals the time for each routine and compares differences in performance. There's a few odd cases where the 2nd one out-performs the first one, but generally not having to count and have a perfect size is a *small* bit faster. Overall though, after 4GB of replacements, the total time is less than a second difference on my laptop.

The first is 3.8 seconds, the second is 4.6 seconds and no pass is as much as 0.1 second faster/slower than the other version.

For a "plug-and-go" routine, like in a library or such, I'd go with something like this. For a "quick-n-dirty" personal project, I'd do like you did -- just set a buffer large enough to handle the change and go with it.

Several folks are saying they'll swap to this routine. They may need to consider which would work best for them. The first is faster, but might overflow the buffer in various situations. The second is a *wee* bit slower, but is safer in more use cases.

It's always nice for folks to have options. (Though rename the SteveReplace, if anyone wants to copy it. That's waaay too cheesy of a name -- even for me! LOL! I just named it *something* for testing purposes.) Wink
Reply


Messages In This Thread
Fast replace$() function - by mdijkens - 04-15-2025, 10:00 AM
RE: Fast replace$() function - by bplus - 04-15-2025, 10:34 AM
RE: Fast replace$() function - by hsiangch_ong - 04-18-2025, 06:04 PM
RE: Fast replace$() function - by mdijkens - 04-18-2025, 07:31 PM
RE: Fast replace$() function - by SMcNeill - 04-18-2025, 08:29 PM
RE: Fast replace$() function - by mdijkens - 04-18-2025, 09:08 PM
RE: Fast replace$() function - by SMcNeill - 04-19-2025, 08:48 AM
RE: Fast replace$() function - by madscijr - 04-18-2025, 11:07 PM
RE: Fast replace$() function - by mdijkens - 04-19-2025, 10:19 AM
RE: Fast replace$() function - by hsiangch_ong - 04-19-2025, 05:23 PM
RE: Fast replace$() function - by mdijkens - 04-19-2025, 06:27 PM



Users browsing this thread: 4 Guest(s)