Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Are sub-strings strings?
#1
I often need to swap two sections of a string, as in the snippet below.
Wiki says "The SWAP statement is used to exchange two variable or array element values".
I find I can only do this by using a temporary variable, so I need 3 lines of code instead of 1.

Is a part of a string a variable? 
If not, maybe the Wiki could clarify this, to save L-Platers like me a lot of time experimenting?

(This is a very simple example, but others can be more significant).
T$ = "ABCDEFG"
Print T$
Swap mid$(T$,2,1) ,mid$(T$,5,1)                   <--   this line is not allowed
Print T$

Tmp$ = Mid$(T$, 2, 1)
Mid$(T$, 2, 1) = Mid$(T$, 5, 1)
Mid$(T$, 5, 1) = Tmp$
Print T$
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, Western Australia.) Big Grin
Please visit my Website at: http://oldendayskids.blogspot.com/
Reply
#2
(12-26-2025, 04:14 AM)PhilOfPerth Wrote: I often need to swap two sections of a string, as in the snippet below.
Wiki says "The SWAP statement is used to exchange two variable or array element values".
I find I can only do this by using a temporary variable, so I need 3 lines of code instead of 1.

Is a part of a string a variable? 
If not, maybe the Wiki could clarify this, to save L-Platers like me a lot of time experimenting?

(This is a very simple example, but others can be more significant).
T$ = "ABCDEFG"
Print T$
Swap mid$(T$,2,1) ,mid$(T$,5,1)                   <--   this line is not allowed
Print T$

Tmp$ = Mid$(T$, 2, 1)
Mid$(T$, 2, 1) = Mid$(T$, 5, 1)
Mid$(T$, 5, 1) = Tmp$
Print T$
   The Mid$ (and Left and Right) actually carve out a temporary buffer with the data.      You could do what you are looking to do with a FIXED LENGTH STRING only and addressing it with a MEM type variable.    In that case you would treat it as an array of _unsigned _bytes not as a STRING.      You can't use _MEM with a Dynamic string because QB64PE does garbage collection on those and they may actually Move in Memory from one call to the next !

You really wouldn't use SWAP though. But _MEMGET & _MEMPUT ! If your code isn't speed critical it's probably easier to code it with just the temporary 3rd variable !
Reply
#3
(12-26-2025, 04:34 AM)ahenry3068 Wrote:
(12-26-2025, 04:14 AM)PhilOfPerth Wrote: I often need to swap two sections of a string, as in the snippet below.
Wiki says "The SWAP statement is used to exchange two variable or array element values".
I find I can only do this by using a temporary variable, so I need 3 lines of code instead of 1.

Is a part of a string a variable? 
If not, maybe the Wiki could clarify this, to save L-Platers like me a lot of time experimenting?

(This is a very simple example, but others can be more significant).
T$ = "ABCDEFG"
Print T$
Swap mid$(T$,2,1) ,mid$(T$,5,1)                   <--   this line is not allowed
Print T$

Tmp$ = Mid$(T$, 2, 1)
Mid$(T$, 2, 1) = Mid$(T$, 5, 1)
Mid$(T$, 5, 1) = Tmp$
Print T$
   The Mid$ (and Left and Right) actually carve out a temporary buffer with the data.      You could do what you are looking to do with a FIXED LENGTH STRING only and addressing it with a MEM type variable.    In that case you would treat it as an array of _unsigned _bytes not as a STRING.      You can't use _MEM with a Dynamic string because QB64PE does garbage collection on those and they may actually Move in Memory from one call to the next !

You really wouldn't use SWAP though.  But _MEMGET & _MEMPUT  !      If your code isn't speed critical it's probably easier to code it with just the temporary 3rd variable !

Thanks ahenry. I get it; I'm telling it to swap two "temporary" pieces of data. I'll stay with my Temp method then.
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, Western Australia.) Big Grin
Please visit my Website at: http://oldendayskids.blogspot.com/
Reply
#4
Code: (Select All)

Dim Shared S As String * 80
Dim Shared Sm As _MEM

Sm = _Mem(S)

S = "ABCDEFGHIJKLMNOPQRSTUVWXYZ..1234567890"

Print S
Print
SWAPCHARS_S 2, 10

SWAPCHARS_S 1, 22

Print S
End

Sub SWAPCHARS_S (INDX1 As Integer, INDX2 As Integer)
    Dim B As _Unsigned _Byte
    Dim B2 As _Unsigned _Byte

    _MemGet Sm, Sm.OFFSET + (INDX1 - 1), B
    _MemGet Sm, Sm.OFFSET + (INDX2 - 1), B2

    _MemPut Sm, Sm.OFFSET + (INDX1 - 1), B2
    _MemPut Sm, Sm.OFFSET + (INDX2 - 1), B
End Sub
Reply
#5
If speed is a concern, I'd make the temp string a fixed string of enough size for all use cases.

DIM temp AS STRING * 100
Mid$(Temp,1,1) = Mid$(T$, 2, 1)
Mid$(T$, 2, 1) = Mid$(T$, 5, 1)
Mid$(T$, 5, 1) = Mid$(Temp, 1, 1)

No string allocation, concatenation, cleanup required.  I imagine it'd be a rather speedy process naturally.
Reply
#6
@ahenry3068 

I really like the _mem approach, so I decided to tackle the ridiculous limit on strings. I’ve modified the program to support dynamic strings since the length is known, even if it varies. It seems to work fine. For now, at least...


Code: (Select All)

Dim S As String

S = "ABCDEF "
Print S
Print
SwapChars S$, 2, 3 'ACBDEF
Print S

SwapChars S$, 3, 5 'ACEDBF'

Print S
End

Sub SwapChars (s As String, idx1 As Long, idx2 As Long)
    Dim L As Long: L = Len(s)
    If idx1 < 1 Or idx2 < 1 Then Exit Sub
    If idx1 > L Or idx2 > L Then Exit Sub
    If idx1 = idx2 Then Exit Sub

    Dim m As _MEM
    m = _MemNew(L)

    ' copy string data to own buffer
    _MemPut m, m.OFFSET, s

    Dim b1 As _Unsigned _Byte, b2 As _Unsigned _Byte
    _MemGet m, m.OFFSET + (idx1 - 1), b1
    _MemGet m, m.OFFSET + (idx2 - 1), b2
    _MemPut m, m.OFFSET + (idx1 - 1), b2
    _MemPut m, m.OFFSET + (idx2 - 1), b1

    ' construct new string
    s = Space$(L)
    Dim i As Long, bt As _Unsigned _Byte
    For i = 0 To L - 1
        _MemGet m, m.OFFSET + i, bt
        Mid$(s, i + 1, 1) = Chr$(bt)
    Next

    _MemFree m
End Sub


Reply
#7
Here is the XOR method of swap.

Code: (Select All)
T$ = "ABCDEFG"
PRINT T$
ASC(T$, 2) = ASC(T$, 2) XOR ASC(T$, 5)
ASC(T$, 5) = ASC(T$, 2) XOR ASC(T$, 5)
ASC(T$, 2) = ASC(T$, 2) XOR ASC(T$, 5)
PRINT T$
Reply
#8
Hey, @Petr!  I found your _MEM code interesting so I played around with it to let me add any new characters in a string.  There are other ways to do this, but making these kinds of things help me get a better grasp on using functions I'm not very experienced with.  I *think* these are working right...

- Dav

Code: (Select All)

Dim S As String
S = "ABCDEF"

Print S ' ABCDEF
Print "size:"; Len(S)

MemStrReplace S, 3, "XXXX"

Print S ' ABXXXXDEF
Print "size:"; Len(S)

MemStrInsert S, 3, "(inserted)"

Print S ' AB(inserted)XXXXDEF
Print "size:"; Len(S)

MemStrReplace S, 13, "" 'do this way to remove character from string

Print S 'AB(inserted)XXXDEF (one X removed)
Print "size:"; Len(S)


Sub MemStrReplace (s As String, idx As Long, ReplaceStr As String)
    Dim L As Long: L = Len(s)
    Dim ReplaceLen As Long: ReplaceLen = Len(ReplaceStr)

    If idx < 1 Or idx > L Then Exit Sub

    'make new length
    Dim newL As Long: newL = L - 1 + ReplaceLen
    Dim m As _MEM: m = _MemNew(newL)

    'copy string before the replacement point
    _MemPut m, m.OFFSET, Left$(s, idx - 1)

    'replace character here with the replacement string
    _MemPut m, m.OFFSET + (idx - 1), ReplaceStr
    'copy string after replacement point
    _MemPut m, m.OFFSET + (idx - 1) + ReplaceLen, Mid$(s, idx + 1)

    'build the new string
    s = Space$(newL)
    Dim i As Long, bt As _Unsigned _Byte
    For i = 0 To newL - 1
        _MemGet m, m.OFFSET + i, bt
        Mid$(s, i + 1, 1) = Chr$(bt)
    Next

    _MemFree m
End Sub

Sub MemStrInsert (s As String, idx As Long, InsertStr As String)
    Dim L As Long: L = Len(s)
    Dim InsertLen As Long: InsertLen = Len(InsertStr)

    If idx < 1 Or idx > L + 1 Then Exit Sub

    Dim newL As Long: newL = L + InsertLen
    Dim m As _MEM
    m = _MemNew(newL)

    'copy original string before insertion (left side)
    _MemPut m, m.OFFSET, Left$(s, idx - 1)

    'insefrt new string here
    _MemPut m, m.OFFSET + (idx - 1), InsertStr

    'copy the rest of the original string (right side)
    _MemPut m, m.OFFSET + (idx - 1) + InsertLen, Right$(s, L - (idx - 1))

    'make the new string
    s = Space$(newL)
    Dim i As Long, bt As _Unsigned _Byte
    For i = 0 To newL - 1
        _MemGet m, m.OFFSET + i, bt
        Mid$(s, i + 1, 1) = Chr$(bt)
    Next

    _MemFree m
End Sub

Find my programs here in Dav's QB64 Corner
Reply
#9
Guys, let me showcase something for you, using the code @Petr wrote to compare:

Code: (Select All)
Dim S As String

S = "ABCDEF "
Print S
Print
SwapChars S$, 2, 3 'ACBDEF
Print "SwapChars", S
AscSwap S$, 2, 3 'back to ABCDEF
Print "AscSwap", S

SwapChars S$, 3, 5 'ABEDDF'
Print "SwapChars", S
AscSwap S$, 3, 5 'back to ABCDEF
Print "AscSwap", S


'some time testing
limit1 = 10000
limit2 = 1000

t1# = Timer
For i = 1 To limit1
For j = 1 To limit2
SwapChars S$, 1, 2
Next
Next
t2# = Timer
For i = 1 To limit1
For j = 1 To limit2
AscSwap S$, 1, 2
Next
Next
t3# = Timer

Print Using "###.##### seconds with SwapChars"; t2# - t1#
Print Using "###.##### seconds with AscSwap"; t3# - t2#




End


Dim temp As String * 100
Sub AscSwap (s As String, c1 As Long, c2 As Long)
Static temp As _Unsigned _Byte 'no need to create and free this byte over and over
temp = Asc(s, c1)
Asc(s, c1) = Asc(s, c2)
Asc(s, c2) = temp
End Sub



Sub SwapChars (s As String, idx1 As Long, idx2 As Long)
Dim L As Long: L = Len(s)
If idx1 < 1 Or idx2 < 1 Then Exit Sub
If idx1 > L Or idx2 > L Then Exit Sub
If idx1 = idx2 Then Exit Sub

Dim m As _MEM
m = _MemNew(L)

' copy string data to own buffer
_MemPut m, m.OFFSET, s

Dim b1 As _Unsigned _Byte, b2 As _Unsigned _Byte
_MemGet m, m.OFFSET + (idx1 - 1), b1
_MemGet m, m.OFFSET + (idx2 - 1), b2
_MemPut m, m.OFFSET + (idx1 - 1), b2
_MemPut m, m.OFFSET + (idx2 - 1), b1

' construct new string
s = Space$(L)
Dim i As Long, bt As _Unsigned _Byte
For i = 0 To L - 1
_MemGet m, m.OFFSET + i, bt
Mid$(s, i + 1, 1) = Chr$(bt)
Next

_MemFree m
End Sub

Mem is great and handy and dandy and all, but it's not always the end all, be all of universal truths. And you guys should know, I'm as much of a believer of _MEM as anybody. There are things that it does for us that nothing else can do or compare with.

But..... Run the above. And see if you don't end up with something like the following results as well:

Quote: 1.09766 seconds with SwapChars
0.05859 seconds with AscSwap
Reply
#10
+1 Steve for doing a real timed test.

So looks like Mem stuff doesn't cut the time down in this case, like with Circle Fill timed experiments.
  724  855  599  923  575  468  400  206  147  564  878  823  652  556 bxor cross forever
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Print strings with accents and special chars Ikerkaz 8 667 12-20-2025, 09:28 PM
Last Post: TempodiBasic

Forum Jump:


Users browsing this thread: 1 Guest(s)