Page 1 of 2

New commands PureBasic: StringField, Space, byte-calc

Posted: Mon Oct 16, 2006 1:41 pm
by AND51
Hello to everybody!

This is my first post in the english forum. I'm from the german forum. :wink:
In fact, I'm from Germany. :)

I suggest these procedures to be new commands in the next PureBasic version:
  • StringField_InsertString() — Insert a field before an other field
  • StringField_SwapFields() — Swap two fields
  • StringField_RemoveField() — Remove the given field
  • Space2() — Similar to Space(), but returns any letters using 3 different, optimized methods
  • bytecalc() — Converts a quad number in bytes to the biggest possible device (KB, MB...)
The original Post can be found here: http://www.purebasic.fr/german/viewtopi ... ight=AND51

I don't mind if these code will be implemented, but optimized by other people. NicTheQuick from the german forum tried to optimize my procedures by using a lot of *Pointer. He had no success, my code beat him (I won the "contest" :wink: ).

A great advantage of my code is, that it don't makes any use of *pointers and *buffers. If I need to cut a string, for example, I use Left(), Right(), RTrim() and LTrim().

It's also very improtant to know that Right() is faster than Left(). Similar to RTrim() being faster than LTrim() / Trim(). In my code I payed attention to these facts - that's why my code should be optimized.

Note: Space() is still faster than Space2(), but only if you want a string filled with space-letters. However, Space2() is the fastest way to fill a string with "PB" (for example). But only, if the modulo specified length of the string and the length of the given string is zero (see code to understand this strange sentence :lol: ).

Note: I was told that RemoveField was counting/working wrong, but I cannot detect any bugs. It works fine on my PC.


Note: My StringField-Funtions start couting at zero (0). The normal StringField() starts counting at one (1). Don't swap this!

Code: Select all

#Franz="Franz jagt im komplett verwahrlosten Taxi quer durch Bayern." 
#Fuchs="The quick brown fox jumps over the lazy dog." 
#Jack="Jackdaws loves my big sphinx of quarz." 


; Define your own test-string: 
#Teststring=#franz 

Procedure.s StringField_InsertString(String$, InsertString$, Index=1, Separator$=" ") ; by AND51 
   Protected n.l, position.q 
   If Index > CountString(String$, Separator$) And Not Right(String$, Len(Separator$)) = Separator$ 
      String$+Separator$ 
   EndIf 
   If FindString(String$, Separator$, 1) 
      For n=1 To Index 
         position=FindString(String$, Separator$, position+1) 
      Next 
      ProcedureReturn Left(String$, position)+InsertString$+Separator$+Right(String$, IntQ(Len(String$))-position) 
   Else 
      ProcedureReturn String$ 
   EndIf 
EndProcedure 

Debug StringField_InsertString(#Teststring, "PureBasic", 1, ".") 

Procedure.s StringField_SwapFields(String$, FieldA, FieldB, Separator$=" ") ; by AND51
	If FieldA <> FieldB
		String$=Separator$+String$+Separator$
		If FieldA > FieldB
			Swap FieldA, FieldB
		EndIf
		Protected FieldA$=StringField(String$, FieldA+1, Separator$), FieldB$=StringField(String$, FieldB+1, Separator$)
		FieldA=FindString(String$, FieldA$, 1)
		FieldB=FindString(String$, FieldB$, 1)
		ProcedureReturn Mid(Left(String$, FieldA-1)+FieldB$+Mid(String$, FieldA+Len(FieldA$), FieldB-FIeldA-Len(FieldA$))+FieldA$+Right(String$, Len(String$)-(FieldB+Len(FieldB$))+1), Len(Separator$)+1, Len(String$)-Len(Separator$)*2)
	Else
		ProcedureReturn String$
	EndIf
EndProcedure
Debug StringField_SwapFields(#Teststring, 7, 1) 

Procedure.s StringField_RemoveField(String$, Index, Separator$=" ") ; by AND51 
   Protected n.l=CountString(String$, Separator$), position.q 
   If Index > n 
      Index=n 
   EndIf 
   For n=1 To Index 
      position=FindString(String$, Separator$, position+1) 
   Next 
   ProcedureReturn Left(String$, position)+Right(String$, Len(String$)-(position+Len(StringField(String$, Index+1, Separator$)))-Len(Separator$)) 
EndProcedure 

Debug StringField_RemoveField(#Teststring, 3) 

Procedure.s Space2(Length, Fill$) ; by AND51 
   Protected space.s, n.l 
   If Not Length % Len(Fill$) And RemoveString(Fill$, " ") 
      space=Space(Length*Len(Fill$)) 
      ReplaceString(space, Space(Len(Fill$)), Fill$, 2) 
   ElseIf RTrim(Fill$) 
      For n=1 To Length 
         space+Fill$ 
      Next 
   Else 
      space=Space(Length*Len(Fill$)) 
   EndIf 
   ProcedureReturn space 
EndProcedure 

Debug Space2(34, "AB") ; 'In Place'-replace, if Length % Len(Fill$) = 0 (see MODULO-Operator).
Debug space2(3, "PureBasic")
Another kind of "contest" can be found here: http://www.purebasic.fr/german/viewtopi ... ight=AND51
This is the most optimized byte-calc function which has ever been written :wink:
It turns a number into the biggest device. For emaple, it turns 4096 into "4 KB". Optional comma-decimals possible.

Note: If this code doesn't seem to work, remove the PeekQ() command from the second line.

Code: Select all

Procedure.s byterechner(byte.q, NbDecimals.b=0) 
   Protected bytes.d=PeekQ(@byte), unit.b=Round(Log(bytes)/Log(1024), 0) 
   ProcedureReturn StrD(Bytes/Pow(1024, unit) , NbDecimals*(unit And 1))+" "+StringField("Byte,KB,MB,GB,TB,PB,EB", unit+1, ",") 
EndProcedure

  • I hope, you like these codes.
    @ PB-Team: What do you think? Have these codes a chance? :)

RemoveField corrected, thx!
SwapField corrected. thx to whilbert

Posted: Mon Oct 16, 2006 1:50 pm
by thamarok
For Space2(), wouldn't this be easier?

Code: Select all

Macro Space2(Length, Character)
 LSet("", Length, Character)
EndMacro
EDIT: I see that with my macro I can't do this:

Code: Select all

PBPBPB
But instead I get this

Code: Select all

PPP
If I try this

Code: Select all

Debug Space2(3, "PB")
But, my macro would be logical with the Space() function, as they both would fill a string with a character.

Posted: Mon Oct 16, 2006 2:07 pm
by AND51
thamarok wrote:For Space2(), wouldn't this be easier?

Code: Select all

Macro Space2(Length, Character)
 LSet("", Length, Character)
EndMacro
EDIT: I see that with my macro I can't do this:

Code: Select all

PBPBPB
That's the fact. I also just discovered this question.
Thank you for your idea.

Your idea is right, but did you see the difference between Space() and Space2()?

Code: Select all

Debug Len(Space(128)) ; will be 128
Debug Len(Space2("  ", 128)) ; 2 (!) spaces inside double quotes - result will be 256
My code creates a new string and fills it X times with Fill$. In contrast to Space(), who creates a string being X characters long. So it's possible, that you can also give my function two spaces (see example above).
Moreover, My procedure is optimized: It recognizes, if Length and Len(Fill$) aré BOTH even or odd.

So Space2(100, "ABC") will be done by FOR/NEXT (100=even, Len("ABC")=odd). (slow)
But Space2(100, "AB") will be done by the ReplaceString(). Look at the help, you can give ReplaceString() some special parameters, to access the "in place" replacing, if mode is set to '2'.

Posted: Mon Oct 16, 2006 2:09 pm
by thamarok
I'm going on a challenge to make the most optimized Space2() function.
@Everybody: Fell free to contribute, let's see who wins :twisted:

Oh and AND51, you have some great StringField functions there!

Posted: Mon Oct 16, 2006 2:14 pm
by AND51
OK, let's do a contest. But note, that I still call PB-Team for implementing this functions into PB!

As I said, I would like to see this functions in next PB version, also, if they are improved by any other guys.


@ thamarok: Contest? OK. Two rules:
  • Play fair :wink:
  • Space2(128, "AB") must not be 128 chars long. It must be 256 chars long. I hope, you know what I am aiming at! So, Space2() must fill a string X times with Fill$! :o

Posted: Mon Oct 16, 2006 2:16 pm
by AND51
thamarok wrote:Oh and AND51, you have some great StringField functions there!
Thank you very much.

German forum: Sombody said to me: "I never used StringField()."
My answer: "I can't imagine a life without StringField()..." :mrgreen:

Posted: Mon Oct 16, 2006 2:20 pm
by thamarok
AND51 wrote:OK, let's do a contest. But note, that I still call PB-Team for implementing this functions into PB!

As I said, I would like to see this functions in next PB version, also, if they are improved by any other guys.


@ thamarok: Contest? OK. Two rules:
  • Play fair :wink:
  • Space2(128, "AB") must not be 128 chars long. It must be 256 chars long. I hope, you know what I am aiming at! So, Space2() must fill a string X times with Fill$! :o
The first entry :D !
Here's my contribution:

Code: Select all

Procedure$ Space2(Length, String$)
Protected SpaceString$, i
 For i=1 To Length
  SpaceString$+String$
 Next
 ProcedureReturn SpaceString$
EndProcedure

Debug Space2(2, "Pure Basic ")
Debug Space2(2, "Rules! ")
Debug Len(Space2(128, "AB")) ; 256
Well, ? :twisted:

EDIT: Here is the dirty one-line version of my code above:

Code: Select all

Procedure$ Space2(len, sx$):Protected sy$,i:For i=1 To len:sy$+sx$:Next:ProcedureReturn sy$:EndProcedure

Debug Space2(2, "Pure Basic ") 
Debug Space2(2, "Rules! ") 
Debug Len(Space2(128, "AB")) ; 256
One-line functions are my ardour :P

Posted: Mon Oct 16, 2006 2:42 pm
by AND51
Updated:
:P Can be made smaller / faster easyly:

Code: Select all

Procedure$ Space2(Length, String$) 
 For i=1 To Length 
  String$+String$ 
 Next 
 ProcedureReturn String$ 
EndProcedure 
Moreover, you must protect everything or nothing (you fogot to protect i).

I must go cooking, so I haven't enoug time left to make a speed test, but I think, my procedure is faster :P

Look at my big source in first post. You just used my 2nd method in ElseIf-block. You don't use either the optimized method in If-Block nor do you use the "normal" Space()-Method in Else-Block. So, I think, my original code is still the fastest.

Edit: Let's do this contest without one:line, okay? (refers to rule no.1 => Play fair!) :wink: :wink: :wink:

Posted: Mon Oct 16, 2006 3:05 pm
by thamarok
AND51 wrote::P Can be made smaller / faster easyly:

Code: Select all

Procedure$ Space2(Length, String$) 
Protected SpaceString$ 
 For i=1 To Length 
  SpaceString$+String$ 
 Next 
 ProcedureReturn SpaceString$ 
EndProcedure 
Moreover, you must protect everything or nothing (you fogot to protect i).

I must go cooking, so I haven't enoug time left to make a speed test, but I think, my procedure is faster :P

Look at my big source in first post. You just used my 2nd method in ElseIf-block. You don't use either the optimized method in If-Block nor do you use the "normal" Space()-Method in Else-Block. So, I think, my original code is still the fastest.

Edit: Let's do this contest without one:line, okay? (refers to rule no.1 => Play fair!) :wink: :wink: :wink:
What the hell?
First you copy my code and say that I didn't use protected on the variable i?
And it was not about optimization, I made the smallest code for this!
And one-liners are cool, why the hell do you want me to not make them?
Rule 1 says to play fair, one-liners are fair! :evil:

For Mods and Admins: Sorry for my rough reply in this topic, but I think you will understand me. Sorry again!

Posted: Mon Oct 16, 2006 3:12 pm
by nco2k
@AND51
> This is the most optimized byte-calc function which has ever been written
and also the buggiest one. :wink:

try Debug byterechner(20954087, 2) it returns KB instead of MB. try Debug byterechner(21456985147, 2) it returns MB instead of GB. :?

whats the meaning of NbDecimals*(unit > 1 And 1)? why not only using NbDecimals without *(unit > 1 And 1)? why are you using .c? its length is different in unicode mode and may lead into confusion if not aware. better use .b .w .l imho.

dont try to overoptimize something, in almost every case its better to keep the code clean and easy. you wont gain anything by trying to squeeze the whole code into two lines. you will only run into trouble due the missing checks.

just my two cents. :)

c ya,
nco2k

Posted: Mon Oct 16, 2006 3:14 pm
by thamarok
nco2k wrote:@AND51
> This is the most optimized byte-calc function which has ever been written
and also the buggiest one. :wink:

try Debug byterechner(20954087, 2) it returns KB instead of MB. try Debug byterechner(21456985147, 2) it returns MB instead of GB. :?

whats the meaning of NbDecimals*(unit > 1 And 1)? why not only using NbDecimals without *(unit > 1 And 1)? why are you using .c? its length is different in unicode mode and may lead into confusion if not aware. better use .b .w .l imho.

dont try to overoptimize something, in almost every case its better to keep the code clean and easy. you wont gain anything by trying to squeeze the whole code into two lines. you will only run into trouble due the missing checks.

just my two cents. :)

c ya,
nco2k
If you're referring to my code, I posted the original code above my one-liner, I made the one-liner just for fun. (What's the problem with everybody?!)

Posted: Mon Oct 16, 2006 3:26 pm
by nco2k
i wasnt reffering to your code. you sent your post while i was stil writing mine. having a bad day thamarok? :?

> What's the problem with one-liners?!)
they are unprofessional, unflexible and hard to maintenance. but serious i dont care, if someone wants to code that way, its fine by me.

c ya,
nco2k

Posted: Mon Oct 16, 2006 4:07 pm
by AND51
What the hell?
First you copy my code and say that I didn't use protected on the variable i?
And it was not about optimization, I made the smallest code for this!
Sorry. I can understand your point of view. Unfortunately, I had the wrong code in my clipboard. I corrected to make you see what I mean.

In my opinion, not the smallest, but the fastest code is the code that can be declared as "optimized". I discovered this, when there was the byte-calc contest in the german forum. It's no problem for me to turn my byte-calc into a one-liner (without : !!). But then the code get slower! Although I dont' work with variables any more. So you can see: Smallest code <> fastest performance
I would suggest: let's kepp the contest alive! :)
@AND51
> This is the most optimized byte-calc function which has ever been written
and also the buggiest one.

try Debug byterechner(20954087, 2) it returns KB instead of MB. try Debug byterechner(21456985147, 2) it returns MB instead of GB.
Bug fixed. Warum konntest du mir das nicht schon im deutschen Forum sagen? :P

>whats the meaning of NbDecimals*(unit > 1 And 1)?
The meaning is: The second multiplicand (in the bracktes) result in zero, if the unit is "Byte". Zero multipplicated with X is always zero.
This automaticlally switches of numbers after decimal point.
Or do you need something like this: "25.69 Byte", "79.91 Byte", "655.4 Byte"? :lol:

Why am I using .c? Well, .b has a positive range of -127 to +127. So you can have a maximum of 127 positions after decimal point. .c has a range of 0 to 255 (ASCII mode), 0 to 65355 (Unicode). This allowed a greater range and leads to more positions after decimal point, if requested. This is just a funny idea, but worked fine always. Nobody in the german forum had ever complained about this.

@ one-liners: I don't lile them really. It's just confusing, if you put 5 lines into a single line. Furthemore, they save 1 Byte per break:
This method just turns Chr(10)+Chr(13) into Chr(58 ), but only, if you don't type any spaces before or after a colon.

Posted: Mon Oct 16, 2006 4:32 pm
by nco2k
@AND51
[german]
> Warum konntest du mir das nicht schon im deutschen Forum sagen?
ja sry, hatte es net gelesen bzw. getestet gehabt. dachte der thread is schon durch und wird offtopic (passiert so oft) deswegen hatte ich aufgehört ihn zu beobachten. :oops: :lol:
[/german]

> (unit > 1 And 1)
oh now i see.. but in some certain situations i stil got X,XX Byte values, thats why i was wondering. with your updated version it seems to be fixed aswell.

> .c
yes, i know that, what i mean is.. use a type with the same range in ascii and unicode to avoid confusion. it would be better imo.

however keep up the good work. :wink:

c ya,
nco2k

Posted: Mon Oct 16, 2006 5:58 pm
by AND51
OK, I#ll change it to .b which makes the byte-calc perfect... :wink: