StringFields_BF - Module

Share your advanced PureBasic knowledge/code with the community.
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

StringFields_BF - Module

Post by Saki »

StringField_Tool_BF - Module

With integrated search - sort and other functions.

It is extreme fast
You can easily test this.
Load and convert (automatically) a photo as sample with the new BaseU_BF function or the other data functions.
The normal versions uses StringField() PB, the HighSpeed versions uses StringFields_BF.
Converting a large photo with the normal versions takes one or more minutes,
with the HighSpeed versions only a fraction of a second.

viewtopic.php?f=12&t=77374

viewtopic.php?f=12&t=77248

viewtopic.php?f=12&t=77295

The BF function reads in all fields up to the given index.
The fields are already stored in an internal list.
This list then contains every field found.
Empty fields can be skipped automatically when the function is called.
Each field contained in the list can then be retrieved with a function call.
The list can be sorted as desired and also searched automatically.

The function StringFields_BF(string$, ..) can also be changed in seconds,
so that a pointer to a string can be passed StringFields_BF(*string, ..)

Have fun with it

Code: Select all

DeclareModule StringFields_BF
  EnableExplicit
  
  ; Main function - Call firstly
  ; mode = 0 - Add a virtual separator at the first and start the search there
  ;        1 - Start the search with the first separator found
  ;        2 - Add a virtual separator at the end and include it in the search
  ;        3 - Add a virtual separator at the first and the end and include both in the search
  Declare StringFields_BF(string$,               ; String to parse - For speed up you can replace with *string
                          separator$,            ; Separator
                          mode=1,                ; Mode
                          ignore_empty_fields=1, ; Ignore empty fields
                          start_index.q=1,       ; Set the start index
                          end_index.q=-1)        ; Set the end index / -1 = full string size
  
  Declare.s GetStringFields_BF(field) ; Get a selected StringField
  
  Declare GetAmountStringFields_BF() ; Get the StringFields amount
  
  Declare GetEmptyStringFields_BF() ; Get the empty StringFields amount
  
  Declare CountSeparators_BF(string$, separator$) ; Count the separators in a string
  
  Declare FreeAllStringFields_BF() ; Free the actual cached StringField list
  
  Declare SortStringFields_BF(flags.a=0,      ; Flags - (optional) - #PB_Sort_Ascending,  #PB_Sort_Descending, #PB_Sort_NoCase
                              start_field=-1, ; Start field for sort - Ignore with -1
                              end_field=-1)   ; End field for sort   - Ignore with -1
  
  ; Find a string in a StringField
  ; This function give back the Stringfield number or 0
  Declare FindStringFields_BF(find_string$,                    ; Search string
                              start_position=1,                ; Startposition inside a StringField
                              flag.a=#PB_String_CaseSensitive, ; Flag - #PB_String_CaseSensitive (preset), #PB_String_NoCase 
                              start_field=-1,                  ; Ignore with -1
                              end_field=-1)                    ; Ignore with -1
EndDeclareModule

Module StringFields_BF
  ; By Saki - Unicode - This code is free for using and enhancing
  Global NewList index(), NewList indexes.s(), empty_fields.q
  Procedure StringFields_BF(string$, separator$, mode=1, ignore_empty_fields=1, start_index.q=1, end_index.q=-1)
    Select mode
      Case 0 : Protected add_first=1 : Case 2 : Protected add_last=1 : Case 3 : add_first=1 : add_last=1
    EndSelect
    Protected skip_first : If start_index<1 : start_index=1 : EndIf : empty_fields.q=0
    Protected i, ii, iii, iiii, pos_1, pos_2, length_result, comp, count_index, amount_indexes
    Protected len_separator=StringByteLength(separator$), skip_last, *string=@string$
    Protected *separator=@separator$, *pointer.word, byte_pos_last, result$ : If end_index=-1 : end_index=1e18 : EndIf
    If start_index>end_index : start_index=end_index+1 : EndIf : If Not PeekW(*string) : ProcedureReturn 0 : EndIf
    ClearList(index()) : AddElement(index()) : ClearList(indexes()) : AddElement(indexes())
    If comp=CompareMemory(*string, *separator, len_separator) : end_index+1 : count_index+1 : skip_first=1 : EndIf
    If add_first
      If skip_first And start_index : start_index-2 : end_index-1 : EndIf
    Else
      If skip_first And start_index : start_index-1 : EndIf 
    EndIf
    i=-2
    Repeat
      i+2 : comp=CompareMemory(*string+i, *separator, len_separator)
      If comp
        iii=i : count_index+1 : ii+1 : i+len_separator-2 : amount_indexes+1 : AddElement(index()) : index()=i+2
      EndIf 
      *pointer=*string+i+len_separator
    Until count_index>end_index Or Not *pointer\w
    iiii=i : byte_pos_last=iii+len_separator
    If comp=CompareMemory(*string+i-len_separator-1, *separator, len_separator) : skip_last=1 : EndIf
    If end_index>count_index : end_index=count_index : EndIf : amount_indexes=ii : i=skip_first
    If start_index>amount_indexes : start_index=amount_indexes-1 : EndIf : i+start_index+skip_first+skip_last
    If skip_first : i-1 : EndIf : If skip_last : i-1 : EndIf
    If amount_indexes
      Repeat 
        If ListSize(index())>i : SelectElement(index(), i) : pos_1=index() : EndIf
        If ListSize(index())>i+1 : SelectElement(index(), i+1) : pos_2=index() : EndIf
        length_result=(pos_2-pos_1-len_separator)>>1
        If pos_2-pos_1>0
          If length_result>0
            result$=PeekS(*string+pos_1, length_result) : AddElement(indexes()) : indexes()=result$ 
          Else 
            empty_fields+1
            If ignore_empty_fields : result$=#Null$ : Else : result$="" : AddElement(indexes()) : EndIf         
          EndIf
        EndIf
        i+1
      Until i>end_index Or i=amount_indexes
      If add_last And skip_last
        result$=PeekS(*string+byte_pos_last, (iiii-byte_pos_last+len_separator)>>1)
        AddElement(indexes()) : indexes()=result$ 
      EndIf
    EndIf
    ProcedureReturn 1
  EndProcedure
  
  Procedure.s GetStringFields_BF(field)
    If field <1 : ProcedureReturn "" : EndIf : SelectElement(indexes(), field)   
    If field<ListSize(indexes()) : ProcedureReturn indexes() : EndIf
  EndProcedure
  
  Procedure GetAmountStringFields_BF() : ProcedureReturn ListSize(indexes())-1 : EndProcedure 
  
  Procedure GetEmptyStringFields_BF() : ProcedureReturn empty_fields : EndProcedure
  
  Procedure CountSeparators_BF(string$, separator$) : ProcedureReturn CountString(string$, separator$) : EndProcedure
  
  Procedure FreeAllStringFields_BF()
    ClearList(index()) : AddElement(index()) : ClearList(indexes()) : AddElement(indexes()) : ProcedureReturn 1
  EndProcedure
  
  Procedure SortStringFields_BF(flags.a=0, start_field=-1, end_field=-1)
    If start_field>0 And end_field>1 And end_field<=ListSize(indexes())
      SortList(indexes(), flags, start_field, end_field-1) : ProcedureReturn 2
    Else
      SortList(indexes(), flags) : ProcedureReturn 1
    EndIf  
  EndProcedure
  
  Procedure FindStringFields_BF(find_string$,
                                start_position=1,
                                flag.a=#PB_String_CaseSensitive,
                                start_field=-1,
                                end_field=-1)
    Protected i, result$
    If end_field>ListSize(indexes()) : end_field=ListSize(indexes()) : EndIf
    If start_field>0 And end_field>1 : end_field-1
      For i=start_field To end_field
        SelectElement(indexes(), i) : result$=indexes()
        If FindString(result$, find_string$, start_position, flag) : ProcedureReturn i : EndIf
      Next
    EndIf
    ProcedureReturn 0
  EndProcedure 
EndModule
UseModule StringFields_BF

; #################### Demo  part #######################
CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
  
  Define separator$=" "
  Define i, index, result$
  
  Define string$=" Hello i am a splitted String, i am StringFields_BF "
  
  Define multiplier=1 ; Enlarge the Teststring - 15 is about 1.7mb (20=54mb) - Deactivate the debugger for large values
  
  If multiplier>1 : For i=1 To multiplier : string$+string$ : Next i : EndIf
  
  Define len_string=Len(string$)
  
  ; mode = 0 - Add a virtual separator at the first and start the search there
  ;        1 - Start the search with the first separator found
  ;        2 - Add a virtual separator at the end and include it in the search
  ;        3 - Add a virtual separator at the first and the end and include both in the search
  Define mode=1
  
  Define start_index=1
  
  Define end_index=-1 ; Index up to which is searched (Last separator) -1 = full string size, all
  
  Debug "Mode : "+mode
  
  Debug "End Index : "+end_index
  
  Define ignore_empty_fields=1
  
  Define time=ElapsedMilliseconds()
  
  Define parsing_time=ElapsedMilliseconds()
  
  Define amount_fields=StringFields_BF(string$, separator$, mode, ignore_empty_fields, start_index, end_index)
  
  Define parsing_time=ElapsedMilliseconds()-parsing_time
  
  Debug "String parsing time : "+parsing_time
  Debug "String length : "+Len(string$)
  Debug "StringFields found : "+GetAmountStringFields_BF()
  Debug "Empty StringFields found : "+GetEmptyStringFields_BF()
  Debug "=============================="
  Debug "I only display the first nine StringFields here"
  Debug "=============================="
  
  ; Sort the StringFields
  ; Define flags.a=#PB_Sort_Ascending|#PB_Sort_NoCase
  ; Define start_field=1
  ; Define end_field=9
  ; flags (optional) - #PB_Sort_Ascending,  #PB_Sort_Descending, #PB_Sort_NoCase
  ; SortStringFields_BF(flags.a, start_field, end_field)
  
  For index=1 To 9
    result$=GetStringFields_BF(index)
    Debug result$
  Next 
  
  ; Find a string in a StringField
  Define find_string$="am"
  Define start_position=1
  Define flags.a=#PB_Sort_Ascending ; #PB_Sort_NoCase
  Define start_field=1
  Define end_field=9 ; GetAmountStringFields_BF()
  Define found
  Debug "=============================="
  Debug "I only search the first nine StringFields here"
  Debug "=============================="
  Debug "Search for : "+find_string$
  For i=1 To end_field
    found=FindStringFields_BF(find_string$, start_position, flags.a, start_field, end_field)
    If found
      start_field=found+1
      Debug "Found in StringField : "+found
    EndIf
  Next
  
  MessageRequester("Deactivate the Debugger",
                   "String parsing time : "+parsing_time+#LF$+               
                   "String length : "+Len(string$)+#LF$+
                   "StringFields found : "+GetAmountStringFields_BF()+#LF$+
                   "Empty StringFields found : "+GetEmptyStringFields_BF())
CompilerEndIf
Last edited by Saki on Thu Jul 01, 2021 9:39 pm, edited 39 times in total.
地球上の平和
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: StringField_Tool_BF - Module

Post by Kwai chang caine »

MsgBox wrote:String parsing time : 192
String length : 983040
String fields found : 229375
Empty string fields found : 32767
Works here with W10 X64 / v5.73 x86 without Debugger
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: StringField_Tool_BF - Module

Post by Saki »

Thank you very much Kwai.

Yes, let's see if the tool can be useful. :wink:
地球上の平和
Post Reply