Page 1 of 1

String filtering/custom ReplaceString+inplace

Posted: Fri Dec 30, 2016 12:47 pm
by Lunasole
Here is some small procedure I've made daily to filter strings, close to ReplaceString with #PB_String_InPlace flag, but also allowing customization.
Additionaly, it is optimized and fast enough.

// Updated to a much faster version, thanks to Josh

Code: Select all

EnableExplicit

; This proc filters string, leaving only characters allowed in "Select" section
; *S			pointer to a string or memory (must be 0-terminated)
; RETURN:		none, filtered string returned byref
Procedure StringFilter (*S.Character)
   Protected *C.Character = *S
   Repeat
      Select *S\c
         Case 'a' To 'z', 'A' To 'Z', ' ', '0' To '9':
         	*C\c = *S\c
         	*C + SizeOf(Character)
         Case 0:
         	*C\c = 0
         	Break
      EndSelect 
      *S + SizeOf(Character)
   ForEver
EndProcedure


; example
Define A$ = "so*me stri@ng to$ filte%r"
StringFilter(@A$)
Debug A$

Re: String filtering/custom ReplaceString+inplace

Posted: Wed Jan 04, 2017 7:24 pm
by WilliamL
Very interesting!

Thanks :D

Re: String filtering/custom ReplaceString+inplace

Posted: Wed Jan 04, 2017 8:50 pm
by Josh
Hello Luna,

I have been working on this topic lately. Here is my quick and dirty version:

Code: Select all

EnableExplicit


Procedure StringFilter (*Read.Character)
  Define *Write.Character = *Read

  Repeat

    If     *Read\c  = #Null                 : *Write\c = *Read\c : ProcedureReturn
    ElseIf *Read\c  = ' '                   : *Write\c = *Read\c : *Write + SizeOf (Character)
    ElseIf *Read\c >= 'a' And *Read\c <= 'z': *Write\c = *Read\c : *Write + SizeOf (Character)
    ElseIf *Read\c >= 'A' And *Read\c <= 'Z': *Write\c = *Read\c : *Write + SizeOf (Character)
    ElseIf *Read\c >= '0' And *Read\c <= '0': *Write\c = *Read\c : *Write + SizeOf (Character)
    EndIf

    *Read + SizeOf (Character)
  ForEver

EndProcedure



; example
Define A$ {100}
Define timer
Define i

timer = ElapsedMilliseconds()
For i = 1 To 1000000

  A$ = "so*me stri@ng to$ filte%r"
  StringFilter(@A$)

Next
timer = ElapsedMilliseconds() - timer
MessageRequester ("", A$ + #CRLF$ + timer)

Re: String filtering/custom ReplaceString+inplace

Posted: Thu Jan 05, 2017 11:42 am
by Lunasole
Josh wrote:Hello Luna,
I have been working on this topic lately. Here is my quick and dirty version
Thanks, nicely done ^^. That your version is simpler and works ~25% faster.
I've improved my own using the same stuff without PeekC, extra variables, etc.

And got unexpected results in speed -- that version with Select Case became 30% faster then.
Well, maybe because I've moved Case 0 to the end

Code: Select all

EnableExplicit
DisableDebugger
; 1. Initial params and common code
OpenConsole("[Testing Facility v1.0.0.1] :3")
Define Time1, Time2, Counter, Count = 1000000 ; 1kk
Macro TestCode (Time, Code)
	Time = ElapsedMilliseconds()
	For Counter = 1 To Count
		Code
	Next Counter
	Time = ElapsedMilliseconds() - Time
EndMacro

; 2. User code
; --------------------------------------------------- \
; declare someting
Procedure StringFilter (*S.Character)
   Protected *C.Character = *S
   Repeat
      Select *S\c
         Case 'a' To 'z', 'A' To 'Z', ' ', '0' To '9':
         	*C\c = *S\c
         	*C + SizeOf(Character)
         Case 0:
         	*C\c = 0
         	Break
      EndSelect 
      *S + SizeOf(Character)
   ForEver
EndProcedure
Procedure StringFilter2 (*Read.Character)
  Define *Write.Character = *Read

  Repeat

    If     *Read\c  = #Null                 : *Write\c = *Read\c : ProcedureReturn
    ElseIf *Read\c  = ' '                   : *Write\c = *Read\c : *Write + SizeOf (Character)
    ElseIf *Read\c >= 'a' And *Read\c <= 'z': *Write\c = *Read\c : *Write + SizeOf (Character)
    ElseIf *Read\c >= 'A' And *Read\c <= 'Z': *Write\c = *Read\c : *Write + SizeOf (Character)
    ElseIf *Read\c >= '0' And *Read\c <= '0': *Write\c = *Read\c : *Write + SizeOf (Character)
    EndIf

    *Read + SizeOf (Character)
  ForEver

EndProcedure

Define A$
Macro Code1 ; code executed inside cycle 1
	A$ = "so*me stri@ng to$ filte%r"
	StringFilter(@A$)
	; do something-1
EndMacro

Macro Code2 ; code executed inside cycle 2
	A$ = "so*me stri@ng to$ filte%r"
	StringFilter2(@A$)
	; do something-2
EndMacro
; --------------------------------------------------- /

; 3. Execute tests
TestCode(Time1, Code1)
TestCode(Time2, Code2)
; 4. Display results
PrintN("Cycle 1: " + Str(Time1) + "ms")
PrintN("Cycle 2: " + Str(Time2) + "ms")
PrintN("------------")
If Time2 > Time1
	PrintN("First is faster: " + StrF(100.0 - (Time1 / (Time2 / 100.0)), 2) + "%")
ElseIf Time1 > Time2
	PrintN("Second is faster: " +StrF(100.0 - (Time2 / (Time1 / 100.0)), 2) + "%")
Else
	PrintN("Equal results")
EndIf
Input()