[SOLVED] FindString() but specify a string occurrence

Just starting out? Need help? Post your questions and find answers here.
Axolotl
Enthusiast
Enthusiast
Posts: 435
Joined: Wed Dec 31, 2008 3:36 pm

Re: FindString() but specify a string occurrence

Post by Axolotl »

A small addition to Demivecs explanation:
Because you can't use typed pointers with the basic types, these structure types are useful if you want to return multiple values from procedures ....

Code: Select all

Procedure GetSize(*Width.INTEGER, *Height.INTEGER) 
  ; some kind of useless code to demonstrate the Parameter By Ref 
  *Width\i = 800
  *Height\i = 600 
  ProcedureReturn #True 
EndProcedure 

Global w, h 
If GetSize(@w, @h) 
  Debug " set to " + w + ", " + h 
EndIf 
BTW: If you are interested in algorithms you might want to search for Knuth-Morris-Pratt_(KMP) or/and Aho-Corasick.
There is a lot of C-code (to learn from)
Mostly running PureBasic <latest stable version and current alpha/beta> (x64) on Windows 11 Home
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: FindString() but specify a string occurrence

Post by Oso »

idle wrote: Wed Nov 23, 2022 9:28 pm If performance matters pass strings by reference. Use while loops and terminate on null. If you need to do multiple searches of the same data use either a map with duplicates add a linked list of positions or use squint3 with a list of positions
you also get prefix search and sorting for free. [snipped]
Apologies for not acknowledging you sooner Idle and thanks for the comments. To be honest, with these findings I've seen with PB's FindString(), versus memory pointers (ChrisR's example), I'm wondering if this might be worth a rethink. I need to spend more time comparing speed, but it seems that when we use our own pointers and allocated memory, we are still limited by the fact that we're trundling through our own loop, whereas PB's FindString() is doing it at a lower level.

Just for starters, this code is taking just 30 or 40ms to find each string in 10 Mil. characters and that's in the debugger mode. For some reason I can't compile it, as Windows Defender flags it as malware as soon as the compiler finishes. I don't know what's going on, but other PB routines compile fine. :(

Code: Select all

OpenConsole()
basestring.s = Space(10000000) + "This is my test string."

starttim.i = ElapsedMilliseconds()

pos.i = FindString(basestring, " test")
PrintN ("Found sub-string at position " + Str(pos.i))
PrintN ("Time = " + Str(ElapsedMilliseconds()-starttim.i))

starttim.i = ElapsedMilliseconds()

pos.i = FindString(basestring, ".")
PrintN ("Found sub-string at position " + Str(pos.i))
PrintN ("Time = " + Str(ElapsedMilliseconds()-starttim.i))

Input()
User avatar
idle
Always Here
Always Here
Posts: 5042
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: FindString() but specify a string occurrence

Post by idle »

It seems findstrings been improved its still slower than the findata module but it's only ~ 3 times slower.
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: FindString() but specify a string occurrence

Post by Oso »

Axolotl wrote: Thu Nov 24, 2022 5:54 pm A small addition to Demivecs explanation: Because you can't use typed pointers with the basic types, these structure types are useful if you want to return multiple values from procedures ....

Code: Select all

Procedure GetSize(*Width.INTEGER, *Height.INTEGER) 
  ; some kind of useless code to demonstrate the Parameter By Ref 
  *Width\i = 800
  *Height\i = 600 
  ProcedureReturn #True 
EndProcedure 

Global w, h 
If GetSize(@w, @h) 
  Debug " set to " + w + ", " + h 
EndIf 
Thanks Axolotl, yes it helps to see this example. You're effectively writing back the procedure parameters then? The limitation of single value results from procedures has limited me somewhat, since a lot of what I've been working on needs to return several things. But could you do this without the structure? In other words, can you just write back the result to *Width for example?
Because you can't use typed pointers with the basic types
I don't follow the above sentence. I tended to think pointers were just that — a pointer to a memory location, which is always going to be a number?
BTW: If you are interested in algorithms you might want to search for Knuth-Morris-Pratt_(KMP) or/and Aho-Corasick. There is a lot of C-code (to learn from)
Interesting, thanks. This feels rather like going back to study again :D
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: FindString() but specify a string occurrence

Post by Oso »

idle wrote: Thu Nov 24, 2022 10:28 pm It seems findstrings been improved its still slower than the findata module but it's only ~ 3 times slower.
I noticed that ReplaceString is quick also — a similar time. I added the below, because I started to wonder if PB was automatically skipping the 20MB of spaces or something. :D

Code: Select all

basestring.s = ReplaceString(basestring.s, " ", "^")
AZJIO
Addict
Addict
Posts: 1318
Joined: Sun May 14, 2017 1:48 am

Re: FindString() but specify a string occurrence

Post by AZJIO »

As far as I understand FindString also iterates over characters. There is no magic way.
Axolotl
Enthusiast
Enthusiast
Posts: 435
Joined: Wed Dec 31, 2008 3:36 pm

Re: FindString() but specify a string occurrence

Post by Axolotl »

Oso wrote: Thu Nov 24, 2022 10:36 pm ...
But could you do this without the structure? In other words, can you just write back the result to *Width for example?
...
Because you can't use typed pointers with the basic types
...
I don't follow the above sentence. I tended to think pointers were just that — a pointer to a memory location, which is always going to be a number?
Hi Oso,
because you cannot code this with the newer compilers:

Code: Select all

Procedure GetSize_WithCompilerErrorMessage(*Width.i, *Height.i)  
; Pointer with Native Type is not possible! 
; ==> Compiler Error Message: "Native types can't be used with pointers."


Here is an extended example.

Code: Select all

EnableExplicit 

Procedure GetSize(*Width.INTEGER, *Height.INTEGER) 
  ; some kind of useless code to demonstrate the Parameter By Ref 
  Debug #PB_Compiler_Procedure + "() => *W, *H = " + *Width + ", " + *Height + " -- *W\i, *H\i = " + *Width\i + ", " + *Height\i 
  *Width\i = 800
  *Height\i = 600 
  Debug Space(Len(#PB_Compiler_Procedure)) + "   => *W, *H = " + *Width + ", " + *Height + " -- *W\i, *H\i = " + *Width\i + ", " + *Height\i 
  ProcedureReturn #True 
EndProcedure 

Procedure GetSize_differently(*Width, *Height) 
  ; some kind of useless code to demonstrate the Parameter By Ref 
  Debug #PB_Compiler_Procedure + "() => *W, *H = " + *Width + ", " + *Height 
  *Width = 800
  *Height = 600 
  Debug Space(Len(#PB_Compiler_Procedure)) + "   => *W, *H = " + *Width + ", " + *Height 
  ProcedureReturn #True 
EndProcedure 

; Test 
Global w, h  
Debug "" 
If GetSize(@w, @h) 
  Debug " set to " + w + ", " + h 
EndIf 
Debug "" 
If GetSize_differently(@w, @h) 
  Debug " set to " + w + ", " + h 
EndIf 

; >> Debug Output << Window 
; 
; GetSize() => *W, *H = 5368975752, 5368975744 -- *W\i, *H\i = 0, 0
;           => *W, *H = 5368975752, 5368975744 -- *W\i, *H\i = 800, 600
;  set to 800, 600
; 
; GetSize_differently() => *W, *H = 5368975752, 5368975744
;                       => *W, *H = 800, 600
;  set to 800, 600
;
As you can see, with integer variables you can work with pointers to get the same result.
However, you change the address to the memory location and not the content of the memory location. (see the Debug output)
IMHO it's more correct (more beautiful, better, more professional, etc.) to do it like the first way!
How it looks with the other native data types, you can check yourself by extending the example.
Mostly running PureBasic <latest stable version and current alpha/beta> (x64) on Windows 11 Home
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: FindString() but specify a string occurrence

Post by Oso »

Axolotl wrote: Fri Nov 25, 2022 12:43 pm

Code: Select all

Procedure GetSize(*Width.INTEGER, *Height.INTEGER) 
  *Width\i = 800
  *Height\i = 600 
As you can see, with integer variables you can work with pointers to get the same result. However, you change the address to the memory location and not the content of the memory location. (see the Debug output) IMHO it's more correct (more beautiful, better, more professional, etc.) to do it like the first
Thanks Axolotl, I appreciate your efforts to explain this and the example too. I can see the advantage in that you're returning local parameters rather than using global variables, which can lead to unintended variable reuse problems.

To be honest though, I find the approach and syntax to be a little arcane, but perhaps in the fullness of time, when I have years of PB behind me, I'll fully embrace it and regard it as a perfectly elegant solution. I noticed for instance that the suffix ".INTEGER" in the parameters doesn't appear with auto-complete and apart from in the Structure Viewer tool, doesn't seem well documented. It also feels quite odd to me that the parameter has .INTEGER as its suffix but it's \i when you set the variable.

There's just a small note in "Pointers and Memory Access" with a .Point example. It leaves me kind of wanting for more information on this idea. :?
Pointers and structures —
By assigning a structure to a pointer (for example *MyPointer.Point) it allows to access any memory address in a structured way (with the operator '\').
Axolotl
Enthusiast
Enthusiast
Posts: 435
Joined: Wed Dec 31, 2008 3:36 pm

Re: FindString() but specify a string occurrence

Post by Axolotl »

Your are welcome.

Unfortunately, I can't do anything about the syntax.
To be honest, I also had a hard time with the PB dialect for a long time.
But man is a creature of habit and you end up getting used to everything.....

A few thoughts (i guess this is off topic)
From my point of view the pointers are very handy with system functions. As you may know I am on windows and I still use a lot of api functions instead of the PB versions....
Some examples (not running codes) ....

Code: Select all

hMonitor = MonitorFromRect_(*rc, #MONITOR_DEFAULTTONEAREST)         ; find monitor, at least the primary monitor is returned 
; 
GetWindowRect_(hWnd, @rcClient)  ; client window rect, keep the width and hight 
; 
GetWindowPlacement_(hwnd, *wp)  ; needs this declaration: ; wp.WINDOWPLACEMENT 
There are a lot already defined system structures like this

Code: Select all

mi.MONITORINFO 
Protected rc.RECT  
 ... 
If GetMonitorInfo_(hMonitor, @mi)                                   ; fill monitorinfo structure 
      If (Flags & #MONITOR_WORKAREA)
        rcMon = mi\rcWork     ; workarea rectangle without the Taskbar 
      Else 
        rcMon = mi\rcMonitor  ; the entire monitor rectangle  |  <== this is working 
      EndIf 


HINT: If you see an interesting structure, you can check if it exists by simply creating a variable and accessing the member by using \ ....
Mostly running PureBasic <latest stable version and current alpha/beta> (x64) on Windows 11 Home
AZJIO
Addict
Addict
Posts: 1318
Joined: Sun May 14, 2017 1:48 am

Re: FindString() but specify a string occurrence

Post by AZJIO »

Oso
This is a pointer to a structure, so as not to copy the data, but to pass it by reference, they will be changed in the source data at the point of the function call. This method makes it easy to return multiple values. It is convenient to use with strings so as not to copy the string, but to work with the original string.

Code: Select all

Structure INTEGER
	i.i
EndStructure

*Width.INTEGER
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: FindString() but specify a string occurrence

Post by Oso »

Axolotl wrote: Sat Nov 26, 2022 12:04 pm Unfortunately, I can't do anything about the syntax. To be honest, I also had a hard time with the PB dialect for a long time. But man is a creature of habit and you end up getting used to everything.....
Quite true. I remember after a couple of years of using the database Basic that I also work with, I got to the point where I felt the language had been perfectly and logically designed :)

The majority of the syntax in PB, I think is great.
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: FindString() but specify a string occurrence

Post by Oso »

AZJIO wrote: Sat Nov 26, 2022 12:21 pm Oso
This is a pointer to a structure, so as not to copy the data, but to pass it by reference, they will be changed in the source data at the point of the function call. This method makes it easy to return multiple values. It is convenient to use with strings so as not to copy the string, but to work with the original string.

Code: Select all

Structure INTEGER
	i.i
EndStructure

*Width.INTEGER
Thanks AZJIO, I'm learning a little more with each example :) In the above though, as I see it, you've defined INTEGER yourself, so it's user-defined, but Axolotl's example below is using INTEGER straight off in the procedure parameter, suggesting to me that it's a hidden reserved name in PB.

Code: Select all

Procedure GetSize(*Width.INTEGER, *Height.INTEGER) 
Axolotl
Enthusiast
Enthusiast
Posts: 435
Joined: Wed Dec 31, 2008 3:36 pm

Re: FindString() but specify a string occurrence

Post by Axolotl »

Oso wrote: Sat Nov 26, 2022 4:02 pm ....
The majority of the syntax in PB, I think is great.
Well, I haven't comlained and never will.
I'm just a hobby programmer and play around with different languages. However, I build almost all my tools with PB.
And these tools never leave my computers, so I have no experience whatsoever of how such a tool behaves in the wild. :)
Mostly running PureBasic <latest stable version and current alpha/beta> (x64) on Windows 11 Home
AZJIO
Addict
Addict
Posts: 1318
Joined: Sun May 14, 2017 1:48 am

Re: FindString() but specify a string occurrence

Post by AZJIO »

Oso
You can view the structures yourself.
Tools -> Structure Viewer Alt+S
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: FindString() but specify a string occurrence

Post by Oso »

AZJIO wrote: Sat Nov 26, 2022 5:08 pm You can view the structures yourself. Tools -> Structure Viewer Alt+S
Yes, I've looked at the Structure Viewer before. I think it's still a little over my head at the moment. I need to first use structures and become more familiar, but as things stand I haven't had cause to use them. Perhaps it will seem more logical to me when I have a reason to use them. For example, at the moment, I'm not sure about the below, without some background, or for that matter why there isn't also a String equivalent.

Image
Post Reply