Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
String Find and Replace
#1
Code: (Select All)
$Console:Only
t$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZAABVA"
Print Using "There are ## A's in "; String.Find(t$, "A", 0);
Print t$
Print "The first  B is at position "; String.Find(t$, "B", 1)
Print "The second B is at position "; String.Find(t$, "B", 2)
Print "The third  B is at position "; String.Find(t$, "B", 3)
Print
Print "Replace the A's with ' Hello World ', we get:"
t1$ = String.Replace(t$, "A", " Hello World ")
Print t1$


Function String.Find& (Content As String, Search As String, CountTo As Long)
    'If CountTo is 0, this routine will count the number of instances of the search term inside the content string
    'If CountTo is >0, this routine will find the position of that instance, if it exists, inside the search string.
    'For example, CountTo = 2, it'll find the location of the 2nd instance of the search term, skipping the first.
    If CountTo < 0 Then Exit Function 'Can't find a negative position.
    Dim As Long p, l
    If Search$ = "" Then Exit Function
    p = InStr(Content$, Search$)
    l = Len(Search$)
    Do While p& > 0
        Count = Count + 1
        If CountTo = Count Then String.Find = p: Exit Function
        p = InStr(p + l, Content$, Search$)
    Loop
    If CountTo = 0 Then String.Find = Count
End Function

Function String.Replace$ (content$, from$, to$)
    'Inspired by the forum post here: https://qb64phoenix.com/forum/showthread...9#pid33559
    'Original credit goes to mdijkens as I just tweaked it a little to make it a bit more library friendly
    $Checking:Off
    Dim As Long mp, pp, found
    Dim m As _MEM
    found = String.Find(content$, from$, 0)
    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$ = Space$(mp): _MemGet m, m.OFFSET, content2$: _MemFree m
    String.Replace$ = content2$
    $Checking:On
End Function

Two routines in here which may be useful for folks:

String.Find will either tell you how many times something appears inside a string (Good for quick counting of said item.), or else it'll give the position of the Xth item inside that string.

String.Replace is a quick replacement routine which is based off the posts here: https://qb64phoenix.com/forum/showthread...9#pid33559  The main difference is that it properly sizes the return buffer so as to work easier in any library/plug in file.  It's a bit slower than the original, but safer and less memory intensive in most cases.
Reply
#2
Tweaked the routines slightly to be Option _Explicit compatible:

Code: (Select All)
Function String.Find& (Content As String, Search As String, CountTo As Long)
'If CountTo is 0, this routine will count the number of instances of the search term inside the content string
'If CountTo is >0, this routine will find the position of that instance, if it exists, inside the search string.
'For example, CountTo = 2, it'll find the location of the 2nd instance of the search term, skipping the first.
If CountTo < 0 _OrElse Search$ = "" Then Exit Function 'Can't find a negative position.
Dim As Long p, l, count
p = InStr(Content$, Search$)
l = Len(Search$)
Do While p& > 0
count = count + 1
If CountTo = count Then String.Find = p: Exit Function
p = InStr(p + l, Content$, Search$)
Loop
If CountTo = 0 Then String.Find = count
End Function

Function String.Replace$ (content$, from$, to$)
'Inspired by the forum post here: https://qb64phoenix.com/forum/showthread...9#pid33559
'Original credit goes to mdijkens as I just tweaked it a little to make it a bit more library friendly
$Checking:Off
If from$ = "" _OrElse content$ = "" Then Exit Function 'can't replace nothing
Dim As Long mp, pp, found, flen, tlen, p
Dim m As _MEM, content2 As String
found = String.Find(content$, from$, 0)
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 = Space$(mp): _MemGet m, m.OFFSET, content2: _MemFree m
String.Replace$ = content2
$Checking:On
End Function
Reply
#3
@bplus See what you think of this style string replacement:

Code: (Select All)
O$ = "12/24/2025"
Print String.Replace.Part(O$, "...??.....", "??", "31") 'string replace part allows us to set a pattern and change our original
Print String.Replace.Part(O$, "..?..?....", "?", "-") 'in relation to that pattern, which is useful for stuff like:
Print
Print
Print Date$ 'the originial version
Print String.Convert.Date(Date$, "Mm-Dd-Year", "Year-Mm-Dd") 'change the pattern from MM-DD-YYYY to YYYY-MM-DD
Print String.Convert.Date(Date$, "Mm-Dd-Year", "Dd-Mm-Year") 'to the weird other side of the world pattern of DD-MM-YYYY

Function String.Convert.Date$ (Source As String, oFormat As String, nFormat As String)
Dim T As String
T = Source
For i = 1 To Len(T)
T = String.Replace.Part(T, nFormat, Mid$(oFormat, i, 1), Mid$(Source, i, 1))
Next
String.Convert.Date = T
End Function

Function String.Get.Part$ (Source As String, Format As String, Part As String)
'this routine allows us to get partial information from a properly formatted string
'format should be something similar to:
'YYYY/MM/DD
'YY-MM-DD
'or similar. What we're looking for is the PART we specify in that format.
Dim As Long p

p = InStr(UCase$(Format), Part)
If Len(Source) <> Len(Format) _OrElse p = 0 Then
_MessageBox "Bad Format", "Error: Passing String with invalid format to Function String.Get.Part.", "error"
Else
String.Get.Part = Mid$(Source, p, Len(Part))
End If
End Function


Function String.Replace.Part$ (Source As String, Format As String, Part As String, Replacement As String)
'this routine allows us to get partial information from a properly formatted string
'format should be something similar to:
'YYYY/MM/DD
'YY-MM-DD
'or similar. What we're looking for is the PART we specify in that format.
Dim As Long p
Dim As String T
T = Source
p = InStr(Format, Part)
If Len(Source) <> Len(Format) _OrElse p = 0 _OrElse Len(Part) <> Len(Replacement) Then
_MessageBox "Bad Format", "Error: Passing String with invalid format to Function String.Replace.Part.", "error"
Else
Do
Mid$(T, p, Len(Replacement)) = Replacement
String.Replace.Part = T
p = InStr(p + 1, Format, Part)
Loop Until p = 0
End If
End Function

Instead of just saying "Replace CAT with DOG", this lets you specify patterns to replace so you can completely reformat strings and such very quick and easily.

Note that since this requires set patterns, you can't replace "APPLE" with "BANANAORANGE" as the patterns don't match. It shouldn't be too hard to swap it to do such, but that's not something I was looking for here. I'm just looking to set a pattern, a replacement pattern, and then replace those chose parts quickly and easily. Wink
Reply
#4
Man Steve you are really on a roll! Smile

Tonight I am finishing other business but I will be happy to have something to do when insomnia strikes again.
b = b + ...
Reply




Users browsing this thread: 1 Guest(s)