Posts: 799
Threads: 140
Joined: Apr 2022
Reputation:
33
12-26-2025, 04:14 AM
(This post was last modified: 12-26-2025, 04:15 AM by PhilOfPerth.)
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.) 
Please visit my Website at: http://oldendayskids.blogspot.com/
Posts: 243
Threads: 15
Joined: Apr 2024
Reputation:
30
12-26-2025, 04:34 AM
(This post was last modified: 12-26-2025, 04:36 AM by ahenry3068.)
(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 !
Posts: 799
Threads: 140
Joined: Apr 2022
Reputation:
33
(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.) 
Please visit my Website at: http://oldendayskids.blogspot.com/
Posts: 243
Threads: 15
Joined: Apr 2024
Reputation:
30
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
Posts: 3,446
Threads: 376
Joined: Apr 2022
Reputation:
345
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.
Posts: 513
Threads: 65
Joined: May 2022
Reputation:
83
@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
Posts: 163
Threads: 20
Joined: Apr 2022
Reputation:
20
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$
Posts: 811
Threads: 128
Joined: Apr 2022
Reputation:
135
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
Posts: 3,446
Threads: 376
Joined: Apr 2022
Reputation:
345
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
Posts: 4,695
Threads: 222
Joined: Apr 2022
Reputation:
322
12-26-2025, 05:15 PM
(This post was last modified: 12-26-2025, 05:17 PM by bplus.)
+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
|