[Solved ]Multiply String / Equivalent of Space for strings?
[Solved ]Multiply String / Equivalent of Space for strings?
Hi,
coming from GFA Basic there was a command STRING$, so that for example STRING$(5,"123 ") produced a string "123 123 123 123 123 ", just like Space(5) produces a string of five spaces.
I know how to make this with a for/while loop, but is there a better/faster way?
I tried to use LSet() and RSet() for this, but it only accepts one char for filling and no string of multiple chars.
Greetings, Hoerbie
coming from GFA Basic there was a command STRING$, so that for example STRING$(5,"123 ") produced a string "123 123 123 123 123 ", just like Space(5) produces a string of five spaces.
I know how to make this with a for/while loop, but is there a better/faster way?
I tried to use LSet() and RSet() for this, but it only accepts one char for filling and no string of multiple chars.
Greetings, Hoerbie
Last edited by hoerbie on Sun Jul 25, 2021 11:14 am, edited 1 time in total.
Re: Multiply String / Equivalent of Space for strings?
What about this:
Code: Select all
Debug ReplaceString(Space(5), " ", "123 ")
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Re: Multiply String / Equivalent of Space for strings?
Hope this helps:
Edit: Stargate was faster XD
Code: Select all
EnableExplicit
Macro StringRepeat(_count_,_string_)
ReplaceString(Space(_count_)," ",_string_)
EndMacro
Debug StringRepeat(5,"123 ")
End
Re: [Solved ]Multiply String / Equivalent of Space for strings?
Thank you both, I also had the idea of using ReplaceString(Space()) before asking, but just was looking for the best/fast function.
I've now tested with a multiplies from 10 to 100000, and using ReplaceString(Space()) gets really faster than a for/while loop the more strings have to be multiplied.
I've now tested with a multiplies from 10 to 100000, and using ReplaceString(Space()) gets really faster than a for/while loop the more strings have to be multiplied.
Re: [Solved ]Multiply String / Equivalent of Space for strings?
For speed, you can compare it to this:
Code: Select all
Procedure.s StringRepeat(String$, Count.i)
Protected StrLen.i, *Buffer, *Ptr, Result$, i.i
StrLen = StringByteLength(string$)
If StrLen
*Buffer = AllocateMemory(StrLen * Count, #PB_Memory_NoClear)
If *Buffer
*Ptr = *Buffer
Count - 1
CopyMemoryString(@String$, @*Ptr)
For i = 1 To Count
CopyMemoryString(@String$)
Next i
Result$ = PeekS(*Buffer)
FreeMemory(*Buffer)
EndIf
EndIf
ProcedureReturn Result$
EndProcedure
Re: [Solved ]Multiply String / Equivalent of Space for strings?
@infratec: Your code gives a "Overflow in a dynamically allocated memory block." in line 13.
You have to allocate 2 additional bytes for the null-character:
You have to allocate 2 additional bytes for the null-character:
Code: Select all
*Buffer = AllocateMemory(StrLen * Count + SizeOf(Character), #PB_Memory_NoClear)
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Re: [Solved ]Multiply String / Equivalent of Space for strings?
You are right!
But in my tests it worked
But in my tests it worked
Re: [Solved ]Multiply String / Equivalent of Space for strings?
Thanks again! As I've thought of another method reading the help for ReplaceString, I made this little test:
On my Mac and in debug-compile-mode the Memory StringRepeat3 of infratec () seems slower than the ReplaceString methods 1 and 2, and between them sometimes 1 is better and sometimes 2, getting to higher counts 1 seems the fastest.
But all are really faster then a classic loop of adding strings together!
Code: Select all
otxt.s = "123 "
ocnt.i = 100000
Procedure.s StringRepeat1(txt.s, cnt.i)
ProcedureReturn ReplaceString(Space(cnt)," ",txt)
EndProcedure
Procedure.s StringRepeat2(txt.s, cnt.i)
Protected txl.i,new.s
txl = Len(txt)
new = Space(txl*cnt)
ReplaceString(new,Space(txl),txt,#PB_String_InPlace)
ProcedureReturn new
EndProcedure
Procedure.s StringRepeat3(String$, Count.i)
Protected StrLen.i, *Buffer, *Ptr, Result$, i.i
StrLen = StringByteLength(string$)
If StrLen
*Buffer = AllocateMemory(StrLen * Count + SizeOf(Character), #PB_Memory_NoClear)
If *Buffer
*Ptr = *Buffer
Count - 1
CopyMemoryString(@String$, @*Ptr)
For i = 1 To Count
CopyMemoryString(@String$)
Next i
Result$ = PeekS(*Buffer)
FreeMemory(*Buffer)
EndIf
EndIf
ProcedureReturn Result$
EndProcedure
start.i = ElapsedMilliseconds()
ret.s = StringRepeat1(otxt, ocnt)
Debug Str(ElapsedMilliseconds()-start)
start.i = ElapsedMilliseconds()
ret.s = StringRepeat2(otxt, ocnt)
Debug Str(ElapsedMilliseconds()-start)
start.i = ElapsedMilliseconds()
ret.s = StringRepeat3(otxt, ocnt)
Debug Str(ElapsedMilliseconds()-start)
But all are really faster then a classic loop of adding strings together!
Re: [Solved ]Multiply String / Equivalent of Space for strings?
Thanks again! As I've thought of another method reading the help for ReplaceString, I made this little test:
On my Mac and in debug-compile-mode the Memory StringRepeat3 of infratec () seems slower than the ReplaceString methods 1 and 2, and between them sometimes 1 is better and sometimes 2, getting to higher counts 1 seems the fastest.
But all are really faster then a classic loop of adding strings together!
Code: Select all
otxt.s = "123 "
ocnt.i = 100000
Procedure.s StringRepeat1(txt.s, cnt.i)
ProcedureReturn ReplaceString(Space(cnt)," ",txt)
EndProcedure
Procedure.s StringRepeat2(txt.s, cnt.i)
Protected txl.i,new.s
txl = Len(txt)
new = Space(txl*cnt)
ReplaceString(new,Space(txl),txt,#PB_String_InPlace)
ProcedureReturn new
EndProcedure
Procedure.s StringRepeat3(String$, Count.i)
Protected StrLen.i, *Buffer, *Ptr, Result$, i.i
StrLen = StringByteLength(string$)
If StrLen
*Buffer = AllocateMemory(StrLen * Count + SizeOf(Character), #PB_Memory_NoClear)
If *Buffer
*Ptr = *Buffer
Count - 1
CopyMemoryString(@String$, @*Ptr)
For i = 1 To Count
CopyMemoryString(@String$)
Next i
Result$ = PeekS(*Buffer)
FreeMemory(*Buffer)
EndIf
EndIf
ProcedureReturn Result$
EndProcedure
start.i = ElapsedMilliseconds()
ret.s = StringRepeat1(otxt, ocnt)
Debug Str(ElapsedMilliseconds()-start)
start.i = ElapsedMilliseconds()
ret.s = StringRepeat2(otxt, ocnt)
Debug Str(ElapsedMilliseconds()-start)
start.i = ElapsedMilliseconds()
ret.s = StringRepeat3(otxt, ocnt)
Debug Str(ElapsedMilliseconds()-start)
But all are really faster then a classic loop of adding strings together!
Re: [Solved ]Multiply String / Equivalent of Space for strings?
Please disable the debugger when doing speed measurements:
On my system:
Code: Select all
otxt.s = "123 "
ocnt.i = 100000
Procedure.s StringRepeat1(txt.s, cnt.i)
ProcedureReturn ReplaceString(Space(cnt)," ",txt)
EndProcedure
Procedure.s StringRepeat2(txt.s, cnt.i)
Protected txl.i,new.s
txl = Len(txt)
new = Space(txl*cnt)
ReplaceString(new,Space(txl),txt,#PB_String_InPlace)
ProcedureReturn new
EndProcedure
Procedure.s StringRepeat3(String$, Count.i)
Protected StrLen.i, *Buffer, *Ptr, Result$, i.i
StrLen = StringByteLength(string$)
If StrLen
*Buffer = AllocateMemory(StrLen * Count + SizeOf(Character), #PB_Memory_NoClear)
If *Buffer
*Ptr = *Buffer
Count - 1
CopyMemoryString(@String$, @*Ptr)
For i = 1 To Count
CopyMemoryString(@String$)
Next i
Result$ = PeekS(*Buffer)
FreeMemory(*Buffer)
EndIf
EndIf
ProcedureReturn Result$
EndProcedure
OpenConsole()
Define I
start.i = ElapsedMilliseconds()
For I = 1 To 100
ret.s = StringRepeat1(otxt, ocnt)
Next
PrintN( Str(ElapsedMilliseconds()-start) )
start.i = ElapsedMilliseconds()
For I = 1 To 100
ret.s = StringRepeat2(otxt, ocnt)
Next
PrintN( Str(ElapsedMilliseconds()-start) )
start.i = ElapsedMilliseconds()
For I =1 To 100
ret.s = StringRepeat3(otxt, ocnt)
Next
PrintN( Str(ElapsedMilliseconds()-start) )
Input()
303
401
282
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Re: [Solved ]Multiply String / Equivalent of Space for strings?
You can speed it up, by copy the string only once:
It is still save, since at the end of the procedure, the memeory will be released automatically.
My Resuilts:
But your created executable at the end has Debugger off
Code: Select all
Procedure.s StringRepeat3(String$, Count.i)
Protected *Buffer, *Ptr, i.i
*Buffer = AllocateMemory(StringByteLength(string$) * Count + SizeOf(Character), #PB_Memory_NoClear)
If *Buffer
*Ptr = *Buffer
Count - 1
CopyMemoryString(@String$, @*Ptr)
For i = 1 To Count
CopyMemoryString(@String$)
Next i
EndIf
ProcedureReturn PeekS(*Buffer)
EndProcedure
My Resuilts:
With Debugger on, my version needs 3 times longer as the others.271
349
144
But your created executable at the end has Debugger off
Re: [Solved ]Multiply String / Equivalent of Space for strings?
No! Memory, which you allocated by yourself, is not freed at the end of the procedure!
You have to free this memory before leaving the procedure.
An alternative could be, to recycle the memory each time with the Static keyword.
But then once a huge buffer is allocated, it will keep allocated until the program ends.
Code: Select all
Procedure.s StringRepeat4(String$, Count.i)
Protected StrLen.i, *Ptr, i.i
Static *Buffer
StrLen = StringByteLength(string$)
If StrLen
If *Buffer = 0 Or StrLen * Count + SizeOf(Character) > MemorySize(*Buffer)
*Buffer = ReAllocateMemory(*Buffer, StrLen * Count + SizeOf(Character), #PB_Memory_NoClear)
EndIf
If *Buffer
*Ptr = *Buffer
Count - 1
CopyMemoryString(@String$, @*Ptr)
For i = 1 To Count
CopyMemoryString(@String$)
Next i
EndIf
EndIf
ProcedureReturn PeekS(*Buffer)
EndProcedure
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Re: [Solved ]Multiply String / Equivalent of Space for strings?
Another alternative is to use a local array as a buffer.
Code: Select all
Procedure.s StringRepeat(String$, Count.i)
Protected Dim Buffer.c(Len(String$) * Count)
Protected *Ptr = @Buffer(0)
CopyMemoryString(#Empty$, @*Ptr)
While Count
CopyMemoryString(@String$)
Count - 1
Wend
ProcedureReturn PeekS(@Buffer(0))
EndProcedure
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: [Solved ]Multiply String / Equivalent of Space for strings?
Very elegant solution .
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
- NicTheQuick
- Addict
- Posts: 1226
- Joined: Sun Jun 22, 2003 7:43 pm
- Location: Germany, Saarbrücken
- Contact:
Re: [Solved ]Multiply String / Equivalent of Space for strings?
In case you are interested. These are my results. I inreased the loop count.
The difference gets even bigger if you also increase ocnt to ten times its value:
And this is the code:
Code: Select all
788
807
481
351
377
Code: Select all
8488
9142
4978
3512
4192
Code: Select all
otxt.s = "123 "
ocnt.i = 100000;0
Procedure.s StringRepeat1(txt.s, cnt.i)
ProcedureReturn ReplaceString(Space(cnt)," ",txt)
EndProcedure
Procedure.s StringRepeat2(txt.s, cnt.i)
Protected txl.i,new.s
txl = Len(txt)
new = Space(txl*cnt)
ReplaceString(new,Space(txl),txt,#PB_String_InPlace)
ProcedureReturn new
EndProcedure
;infratec: https://www.purebasic.fr/english/viewtopic.php?p=572925#p572925
Procedure.s StringRepeat3(String$, Count.i)
Protected *Buffer, *Ptr, i.i
*Buffer = AllocateMemory(StringByteLength(string$) * Count + SizeOf(Character), #PB_Memory_NoClear)
If *Buffer
*Ptr = *Buffer
Count - 1
CopyMemoryString(@String$, @*Ptr)
For i = 1 To Count
CopyMemoryString(@String$)
Next i
EndIf
ProcedureReturn PeekS(*Buffer)
EndProcedure
;STARGÅTE: https://www.purebasic.fr/english/viewtopic.php?p=572933#p572933
Procedure.s StringRepeat4(String$, Count.i)
Protected StrLen.i, *Ptr, i.i
Static *Buffer
StrLen = StringByteLength(string$)
If StrLen
If *Buffer = 0 Or StrLen * Count + SizeOf(Character) > MemorySize(*Buffer)
*Buffer = ReAllocateMemory(*Buffer, StrLen * Count + SizeOf(Character), #PB_Memory_NoClear)
EndIf
If *Buffer
*Ptr = *Buffer
Count - 1
CopyMemoryString(@String$, @*Ptr)
For i = 1 To Count
CopyMemoryString(@String$)
Next i
EndIf
EndIf
ProcedureReturn PeekS(*Buffer)
EndProcedure
;wilbert: https://www.purebasic.fr/english/viewtopic.php?p=572936#p572936
Procedure.s StringRepeat5(String$, Count.i)
Protected Dim Buffer.c(Len(String$) * Count)
Protected *Ptr = @Buffer(0)
CopyMemoryString(#Empty$, @*Ptr)
While Count
CopyMemoryString(@String$)
Count - 1
Wend
ProcedureReturn PeekS(@Buffer(0))
EndProcedure
OpenConsole()
Define I
start.i = ElapsedMilliseconds()
For I = 1 To 1000
ret.s = StringRepeat1(otxt, ocnt)
Next
PrintN( Str(ElapsedMilliseconds()-start) )
start.i = ElapsedMilliseconds()
For I = 1 To 1000
ret.s = StringRepeat2(otxt, ocnt)
Next
PrintN( Str(ElapsedMilliseconds()-start) )
start.i = ElapsedMilliseconds()
For I =1 To 1000
ret.s = StringRepeat3(otxt, ocnt)
Next
PrintN( Str(ElapsedMilliseconds()-start) )
start.i = ElapsedMilliseconds()
For I =1 To 1000
ret.s = StringRepeat4(otxt, ocnt)
Next
PrintN( Str(ElapsedMilliseconds()-start) )
start.i = ElapsedMilliseconds()
For I =1 To 1000
ret.s = StringRepeat5(otxt, ocnt)
Next
PrintN( Str(ElapsedMilliseconds()-start) )
Input()
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.