Page 1 of 2

Add MSet() function to string library

Posted: Mon Feb 24, 2025 10:42 pm
by Quin
I'm proposing a function similar to RSet or LSet, accept it would pad both sides of your string instead of just one until the specified length is reached.
Not much else needs said I think :D

Re: Add Set() function to string library

Posted: Tue Feb 25, 2025 2:21 am
by BarryG
Good idea! :) I propose the name MSet(), with the "m" for "middle", to match LSet() and RSet().

A workaround for now:

Code: Select all

Procedure.s MSet(text$,length,char$=" ")
  t=Len(text$)
  If t>0 And length>t
    pad=(length-t)/2
    char$=Left(char$,1)
    text$=RSet(char$,pad,char$)+text$+LSet(char$,pad,char$)
    If Len(text$)<length
      text$+char$
    EndIf
  EndIf
  ProcedureReturn text$
EndProcedure

Debug "123456789.123456789.123456789.123456789.123456789."
Debug MSet("pad this to 50 chars",50,"-")
Output:

Code: Select all

123456789.123456789.123456789.123456789.123456789.
---------------pad this to 50 chars---------------

Re: Add Set() function to string library

Posted: Tue Feb 25, 2025 4:17 am
by idle
BarryG wrote: Tue Feb 25, 2025 2:21 am Good idea! :) I propose the name MSet(), with the "m" for "middle", to match LSet() and RSet().

A workaround for now:

Code: Select all

Procedure.s MSet(text$,length,char$=" ")
  t=Len(text$)
  If t>0 And length>t
    pad=(length-t)/2
    char$=Left(char$,1)
    text$=RSet(char$,pad,char$)+text$+LSet(char$,pad,char$)
    If Len(text$)<length
      text$+char$
    EndIf
  EndIf
  ProcedureReturn text$
EndProcedure

Debug "123456789.123456789.123456789.123456789.123456789."
Debug MSet("pad this to 50 chars",50,"-")
Output:

Code: Select all

123456789.123456789.123456789.123456789.123456789.
---------------pad this to 50 chars---------------
nice!

Re: Add Set() function to string library

Posted: Tue Feb 25, 2025 6:29 am
by DarkDragon
Set() could be confused with a set data structure.

Re: Add Set() function to string library

Posted: Tue Feb 25, 2025 11:33 am
by Quin
DarkDragon wrote: Tue Feb 25, 2025 6:29 am Set() could be confused with a set data structure.
True, that's why I like BarryG's naming suggestion. Will update the topic with it :)

Re: Add Set() function to string library

Posted: Tue Feb 25, 2025 11:34 am
by Quin
BarryG wrote: Tue Feb 25, 2025 2:21 am Good idea! :) I propose the name MSet(), with the "m" for "middle", to match LSet() and RSet().

A workaround for now:

Code: Select all

Procedure.s MSet(text$,length,char$=" ")
  t=Len(text$)
  If t>0 And length>t
    pad=(length-t)/2
    char$=Left(char$,1)
    text$=RSet(char$,pad,char$)+text$+LSet(char$,pad,char$)
    If Len(text$)<length
      text$+char$
    EndIf
  EndIf
  ProcedureReturn text$
EndProcedure

Debug "123456789.123456789.123456789.123456789.123456789."
Debug MSet("pad this to 50 chars",50,"-")
Output:

Code: Select all

123456789.123456789.123456789.123456789.123456789.
---------------pad this to 50 chars---------------
Nice function! Thanks for sharing 8)

Re: Add MSet() function to string library

Posted: Tue Feb 25, 2025 1:11 pm
by benubi
Just an other "branchless" version.

Code: Select all

Procedure.s MSet(text$,length,char$=" ")
  Protected l2 =  (length/2) - (Len(text$)/2) 
  ProcedureReturn (LSet("",l2,char$)+Left(text$,length)+LSet("",l2,char$))
EndProcedure

txt$=mset("Hello World",35,"*")
Debug txt$
Debug Len(txt$)

txt$=mset("Hello World",5,"*")
Debug txt$
Debug Len(txt$)
LSet/Rset has no problem accepting negative values, that does the little "trick" above.

Code: Select all

Debug LSet("",-3," ") ; No problem
Debug Space(-3) ; Debugger warning/error

Re: Add MSet() function to string library

Posted: Tue Feb 25, 2025 1:12 pm
by Quin
benubi wrote: Tue Feb 25, 2025 1:11 pm Just an other "branchless" version.

Code: Select all

Procedure.s MSet(text$,length,char$=" ")
  Protected l2 =  (length/2) - (Len(text$)/2) 
  ProcedureReturn Left((LSet("",l2,char$)+Left(text$,length)+LSet("",l2,char$)),length)
EndProcedure

txt$=mset("Hello World",35,"*")
Debug txt$
Debug Len(txt$)

txt$=mset("Hello World",5,"*")
Debug txt$
Debug Len(txt$)
LSet/Rset has no problem accepting negative values, that does the little "trick" above.

Code: Select all

Debug LSet("",-3," ") ; No problem
Debug Space(-3) ; Debugger warning/error
Whoa, that's cool. The more you know! Thanks for sharing :)

Re: Add MSet() function to string library

Posted: Tue Feb 25, 2025 1:16 pm
by benubi
I just modified a little The Left() around all isn't necessary since there's the Left() between the Lset()'s. It may be glitchy (?) because you may want the middle part of "Hello world", "lo wo" or something, and here it returns the left part.

Update: I added Mset2() to return the center part

Code: Select all

Procedure.s MSet(text$,length,char$=" ")
  Protected l2 =  (length/2) - (Len(text$)/2) 
  ProcedureReturn (LSet("",l2,char$)+Left(text$,length)+LSet("",l2,char$))
EndProcedure

Procedure.s MSet2(text$,length,char$=" ")
  Protected l2 =  (length/2) - (Len(text$)/2) 
  Protected m2 = 1 + (Bool(l2<0)*l2*-1)
  ProcedureReturn LSet("",l2,char$)+Mid(text$,m2,length)+LSet("",l2,char$)
EndProcedure


txt$=mset2("Hello World",35,"*")
Debug txt$
Debug Len(txt$)

txt$=mset2("Hello World",5,"*")
Debug txt$
Debug Len(txt$)

Re: Add MSet() function to string library

Posted: Tue Feb 25, 2025 1:26 pm
by BarryG
@benubi: Your code has a bug. It misses a padding character when the string is short:
benubi wrote: Tue Feb 25, 2025 1:16 pm

Code: Select all

Procedure.s MSet(text$,length,char$=" ")
  Protected l2 =  (length/2) - (Len(text$)/2) 
  ProcedureReturn (LSet("",l2,char$)+Left(text$,length)+LSet("",l2,char$))
EndProcedure

Procedure.s MSet2(text$,length,char$=" ")
  Protected l2 =  (length/2) - (Len(text$)/2) 
  Protected m2 = 1 + (Bool(l2<0)*l2*-1)
  ProcedureReturn LSet("",l2,char$)+Mid(text$,m2,length)+LSet("",l2,char$)
EndProcedure

txt$=mset2("Hi",35,"*")
Debug txt$
Debug Len(txt$) ; 34 <- BUG

txt$=mset2("Hi",5,"*")
Debug txt$
Debug Len(txt$) ; 4 <- BUG

Re: Add MSet() function to string library

Posted: Tue Feb 25, 2025 1:32 pm
by benubi
@BarryG thanks for the feedback and the challenge. It makes me feel "competitive" :lol:
Now test this - it has all my "new best tricks" ;)

Code: Select all

Procedure.s MSet2(text$,length,char$=" ")
  Protected l2 =  (length/2) - (Len(text$)/2) 
  Protected m2 = 1 + (Bool(l2<0)*l2*-1)
  ProcedureReturn LSet("",l2,char$)+Mid(text$,m2,length)+LSet("",l2 + (length & 1),char$) ; 
EndProcedure

txt$=mset2("Hi",35,"*")
Debug txt$
Debug Len(txt$) ; 

txt$=mset2("Hi",5,"*")
Debug txt$
Debug Len(txt$) ; 

txt$=mset2("Hi",32,"*")
Debug txt$
Debug Len(txt$) ; 

txt$=mset2("Hi",3,"*")
Debug txt$
Debug Len(txt$) ; 

Re: Add MSet() function to string library

Posted: Tue Feb 25, 2025 2:01 pm
by benubi
This version took me a little longer.
It is "branchless" and uses less String function calls (only 1 Lset to preallocate and pre-fill the result). This should be faster than the previous versions. But in practice I found it impossible to beat PB with most string functions like Hex() or Val() when I tried, the URLEncoders are the exception (I believe windows throttles it because of spam/viri and/or to better sell their faster server versions or so).

Code: Select all

Procedure.s MSet3(text$,length,char$=" ")
  Protected l2   =  (length/2) - (Len(text$)/2) 
  Protected m2   = (Bool(l2<0)*l2*-1)* SizeOf(Character)
  Protected out$ = LSet("",length,char$)
  Protected *Z1.character = @text$ + m2
  Protected *Z2.character = @out$  + (Bool(l2>0)*l2*SizeOf(Character))
  
  While *Z2\c And *Z1\c
    *Z2\c = *Z1\c
    *Z1+SizeOf(Character)
    *Z2+SizeOf(Character)
  Wend 
  
  ProcedureReturn out$
EndProcedure


txt$=mset3("Hi",35,"*")
Debug txt$
Debug Len(txt$) ; 

txt$=mset3("Hi",5,"*")
Debug txt$
Debug Len(txt$) ; 

txt$=mset3("Hi",32,"*")
Debug txt$
Debug Len(txt$) ; 

txt$=mset3("Hi",2,"*")
Debug txt$
Debug Len(txt$) ; 

Re: Add MSet() function to string library

Posted: Wed Feb 26, 2025 1:28 am
by BarryG
Both new versions work great! :)

Re: Add MSet() function to string library

Posted: Wed Feb 26, 2025 2:01 am
by Quin
BarryG wrote: Wed Feb 26, 2025 1:28 am Both new versions work great! :)
Can confirm, incredibly impressive work. Gives me something to work towards in terms of my eventual PB skill level :D

Re: Add MSet() function to string library

Posted: Wed Feb 26, 2025 8:20 am
by PBJim
BarryG wrote: Wed Feb 26, 2025 1:28 am Both new versions work great! :)
Not quite Barry, MSet3() is the only one that works. MSet() and MSet2() fail in the below cases.

Your own MSet() code was actually bug-free as you had anticipated the possibility of odd-numbered lengths, which Benubi hadn't. :D

Code: Select all

Procedure.s MSet(text$,length,char$=" ")
  Protected l2 =  (length/2) - (Len(text$)/2) 
  ProcedureReturn (LSet("",l2,char$)+Left(text$,length)+LSet("",l2,char$))
EndProcedure

Procedure.s MSet2(text$,length,char$=" ")
  Protected l2 =  (length/2) - (Len(text$)/2) 
  Protected m2 = 1 + (Bool(l2<0)*l2*-1)
  ProcedureReturn LSet("",l2,char$)+Mid(text$,m2,length)+LSet("",l2 + (length & 1),char$) ; 
EndProcedure

Procedure.s MSet3(text$,length,char$=" ")
  Protected l2   =  (length/2) - (Len(text$)/2) 
  Protected m2   = (Bool(l2<0)*l2*-1)* SizeOf(Character)
  Protected out$ = LSet("",length,char$)
  Protected *Z1.character = @text$ + m2
  Protected *Z2.character = @out$  + (Bool(l2>0)*l2*SizeOf(Character))
  
  While *Z2\c And *Z1\c
    *Z2\c = *Z1\c
    *Z1+SizeOf(Character)
    *Z2+SizeOf(Character)
  Wend 
  
  ProcedureReturn out$
EndProcedure

Debug "123456789.123456789."
Debug MSet("ABC",8,"-")                 ; Fails

Debug "123456789.123456789."
Debug MSet("ABCD",7,"-")                ; Fails

Debug "===================="

Debug "123456789.123456789."
Debug MSet2("ABC",8,"-")                ; Fails

Debug "123456789.123456789."
Debug MSet2("ABCD",7,"-")

Debug "===================="

Debug "123456789.123456789."
Debug MSet3("ABC",8,"-")

Debug "123456789.123456789."
Debug MSet3("ABCD",7,"-")