Author Topic: Seed parameter in the new _INSTRREV() statement.  (Read 9344 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #30 on: April 09, 2019, 08:49:15 am »
Start moves from left to right, so let's look at an example:

"alphabet"

PRINT _INSTR(3,"alphabet","a")

start in this case is 3.  So basically think of it as:

PRINT _INSTR(LEFT$("alphabet",3), "a").

We'd start at the first letter ("a") and then count to the third letter ("p"), and then see where "a" appears in the "alp" which we're using.


So, to answer your question: start moves from left to right, though we search from right to left.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline codeguy

  • Forum Regular
  • Posts: 174
    • View Profile
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #31 on: April 09, 2019, 04:46:59 pm »
another tactic is string reversal, which lends itself quite nicely to the standard use of INSTR().
Code: QB64: [Select]
  1. my$ = "tom jane fred lois dog cat mouse tom jerry mouse"
  2.  
  3. t& = LEN(my$)
  4.     t& = InStringReverse&(t&, my$, "tom")
  5.     PRINT t&
  6.     IF t& > 0 THEN
  7.         t& = t& - LEN("tom")
  8.     ELSE
  9.         EXIT DO
  10.     END IF
  11. LOOP WHILE t& > 0
  12.  
  13. d$ = StringReverse$(my$, 1, LEN(my$))
  14. r$ = StringReverse$("tom", 1, LEN("tom"))
  15. s& = 1
  16. WHILE INSTR(s&, d$, r$) > 0
  17.     i& = INSTR(s&, d$, r$)
  18.     PRINT i&; LEN(d$) - i& - 1
  19.     s& = i& + LEN(r$)
  20.  
  21. FUNCTION InStringReverse& (start&, x$, f$)
  22.     ps& = start& - LEN(f$) + 1
  23.     DO
  24.         IF ps& > 0 THEN
  25.             IF MID$(x$, ps&, LEN(f$)) = f$ THEN
  26.                 EXIT DO
  27.             ELSE
  28.                 ps& = ps& - 1
  29.             END IF
  30.         ELSE
  31.             EXIT DO
  32.         END IF
  33.     LOOP
  34.     InStringReverse& = ps&
  35.  
  36. FUNCTION StringReverse$ (b$, start&, finish&)
  37.     x$ = b$
  38.     a& = start&
  39.     b& = finish&
  40.     DO WHILE a& < b&
  41.         asca% = ASC(x$, a&)
  42.         ascb% = ASC(x$, b&)
  43.         IF asca% <> ascb% THEN
  44.             ASC(x$, a&) = ascb%
  45.             ASC(x$, b&) = asca%
  46.         END IF
  47.         a& = a& + 1
  48.         b& = b& - 1
  49.     LOOP
  50.     StringReverse$ = x$
  51.     x$ = ""
  52.  
« Last Edit: April 09, 2019, 05:14:16 pm by codeguy »

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #32 on: April 09, 2019, 04:52:13 pm »
Well figuring out how to "adjust my expectations" on this one is difficult. I think it could follow in the lines of QB INSTR() and be a much better keyword. All it needs is that annoying repeating loop eliminated. INSTR() doesn't loop, period. The reverse shouldn't either. As for not being a mirror in regard to the seeding, I have worked all that out. I'm fine with the seed parameter left to right, just like INSTR(), but that repeating crap bears repeating... it's crap!

Anyway, here is what I had to work with to consider how I may or may not want to use this new keyword, along with an alternative function I put together, to do the same as reverse instr(). Notice the difference in the way the standard INSTR() escapes vs what is I needed to add to get _instrrev() to escape properly. If there is a simpler way. I'm all ears, but this it what I came up with for now...

Code: QB64: [Select]
  1. ''strng$ = ",dog,bill,cat,dog,dogfood,pete,steve,bill,cat,dog,dogfood,pete,steve,bill,cat,dog,dogfood,pete,steve,dog,"
  2. ''srch$ = ",dog,"
  3. strng$ = "1234"
  4. LINE INPUT "Search: "; srch$
  5. PRINT "INSTR - Forward!"
  6.     seed& = INSTR(seed&, strng$, srch$)
  7.     IF seed& = 0 THEN EXIT DO
  8.     x$ = MID$(strng$, seed&, LEN(srch$))
  9.     PRINT x$, seed&
  10.     seed& = seed& + LEN(srch$)
  11. PRINT "_INSTRREV - Reverse!"
  12.     seed& = _INSTRREV(seed&, strng$, srch$)
  13.     ' 0 needed for if search term is start of string.
  14.     IF seed& = 0 THEN PRINT "Exits because seed& = 0"
  15.     IF srch$ = "" THEN PRINT "Exits because srch$ = " + CHR$(34) + CHR$(34)
  16.     IF lastseed& - LEN(srch$) <= 0 AND lastseed& <> 0 THEN PRINT "Exits because lastseed& - LEN(srch$) <= 0 AND lastseed& <> 0", lastseed& - LEN(srch$)
  17.     IF seed& = 0 OR srch$ = "" OR lastseed& - LEN(srch$) <= 0 AND lastseed& <> 0 THEN EXIT DO
  18.     x$ = MID$(strng$, seed&, LEN(srch$))
  19.     PRINT x$, seed&
  20.     lastseed& = seed& ' Needed to escape looping if string begins with search term.
  21.     seed& = seed& - LEN(srch$)
  22. PRINT "Pete's instrrev function with SMART escape...": seed& = 0
  23.     seed& = instrrev&(seed&, strng$, srch$)
  24.     IF seed& <= 0 THEN EXIT DO
  25.     x$ = MID$(strng$, seed&, LEN(srch$))
  26.     PRINT x$, seed&
  27.     seed& = LEN(strng$) - seed& + LEN(srch$)
  28. FUNCTION instrrev& (seed&, strng$, srch$)
  29. FOR instrrev& = LEN(strng$) - seed& TO 1 STEP -1
  30.     IF MID$(strng$, instrrev&, LEN(srch$)) = srch$ THEN EXIT FOR
  31. IF srch$ = "" THEN instrrev& = 0
  32.  


The double "" can be removed, so the larger string can be tested with the search term: ",dog,"

If anyone can think of a search that would invalidate any of the three methods coded above, let me know.

Pete
« Last Edit: April 09, 2019, 05:05:01 pm by Pete »
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

FellippeHeitor

  • Guest
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #33 on: April 09, 2019, 05:04:31 pm »
http://qb64.org/wiki/INSTRREV

Example 2: Searching for multiple instances of a substring inside a base string, going from the end to the start.

Code: QB64: [Select]
  1. sentence$ = " This is a string full of spaces, including at start and end... "
  2. PRINT sentence$
  3.     findPrevSpace% = _INSTRREV(findPrevSpace% - 1, sentence$, SPACE$(1))
  4.     IF findPrevSpace% = 0 THEN LOCATE 4, 1: PRINT "No more spaces": EXIT DO
  5.  
  6.     LOCATE 2, findPrevSpace%
  7.     PRINT "^"
  8.     totalSpaces = totalSpaces + 1
  9.  
  10.     IF findPrevSpace% = 1 THEN LOCATE 4, 1: PRINT "Last space found at position 1": EXIT DO
  11. PRINT "Total spaces found: "; totalSpaces

Offline codeguy

  • Forum Regular
  • Posts: 174
    • View Profile
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #34 on: April 09, 2019, 05:05:42 pm »
This method allows use of standard INSTR(). this is the second demo in the above code pared to only what is necessary.
Code: QB64: [Select]
  1. my$ = "tom jane fred lois dog cat mouse tom jerry mouse"
  2. d$ = StringReverse$(my$, 1, LEN(my$))
  3. r$ = StringReverse$("tom", 1, LEN("tom"))
  4. s& = 1
  5. WHILE INSTR(s&, d$, r$) > 0
  6.     i& = INSTR(s&, d$, r$)
  7.     PRINT i&; LEN(d$) - i& - 1
  8.     s& = i& + LEN(r$)
  9.  
  10. FUNCTION StringReverse$ (b$, start&, finish&)
  11.     x$ = b$
  12.     a& = start&
  13.     b& = finish&
  14.     DO WHILE a& < b&
  15.         asca% = ASC(x$, a&)
  16.         ascb% = ASC(x$, b&)
  17.         IF asca% <> ascb% THEN
  18.             ASC(x$, a&) = ascb%
  19.             ASC(x$, b&) = asca%
  20.         END IF
  21.         a& = a& + 1
  22.         b& = b& - 1
  23.     LOOP
  24.     StringReverse$ = x$
  25.     x$ = ""
  26.  
« Last Edit: April 09, 2019, 05:12:48 pm by codeguy »

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #35 on: April 09, 2019, 05:48:40 pm »
I tried the double escape method, which Fell posted, some time ago, but I really wanted to get a single escape line. It works, but unfortunately it is complicated and therefore a bit difficult to remember. With 2 EXIT DO statements. I'd have to end up with something like this...

Code: QB64: [Select]
  1. ' Example with two EXIT DO statements
  2. strng$ = "1234"
  3. LINE INPUT "Search: "; srch$
  4. PRINT "_INSTRREV - Reverse!"
  5.     seed& = _INSTRREV(seed&, strng$, srch$)
  6.     ' 0 needed for if search term is start of string.
  7.     IF seed& = 0 THEN PRINT "Exits because seed& = 0"
  8.     IF srch$ = "" THEN PRINT "Exits because srch$ = " + CHR$(34) + CHR$(34)
  9.     IF seed& = 1 THEN PRINT "Exits after printing because seed& = 1"
  10.     IF seed& = 0 OR srch$ = "" THEN EXIT DO
  11.     x$ = MID$(strng$, seed&, LEN(srch$))
  12.     PRINT x$, seed&
  13.     IF seed& = 1 THEN EXIT DO
  14.     seed& = seed& - LEN(srch$)


Vs this...

Code: QB64: [Select]
  1. ' Example with one EXIT DO statements
  2. strng$ = "1234"
  3. LINE INPUT "Search: "; srch$
  4. PRINT "_INSTRREV - Reverse!"
  5.     seed& = _INSTRREV(seed&, strng$, srch$)
  6.     ' 0 needed for if search term is start of string.
  7.     IF seed& = 0 THEN PRINT "Exits because seed& = 0"
  8.     IF srch$ = "" THEN PRINT "Exits because srch$ = " + CHR$(34) + CHR$(34)
  9.     IF lastseed& - LEN(srch$) <= 0 AND lastseed& <> 0 THEN PRINT "Exits because lastseed& - LEN(srch$) <= 0 AND lastseed& <> 0", lastseed& - LEN(srch$)
  10.     IF seed& = 0 OR srch$ = "" OR lastseed& - LEN(srch$) <= 0 AND lastseed& <> 0 THEN EXIT DO
  11.     x$ = MID$(strng$, seed&, LEN(srch$))
  12.     PRINT x$, seed&
  13.     lastseed& = seed& ' Needed to escape looping if string begins with search term.
  14.     seed& = seed& - LEN(srch$)
  15.  

So same number of lines, but one vs two exit do statements. I still lobby for make _INSTRREV() work more like my function, below...

Code: QB64: [Select]
  1. strng$ = "1234"
  2. LINE INPUT "Search: "; srch$
  3. PRINT "Pete's instrrev function with SMART escape...": seed& = 0
  4.     seed& = instrrev&(seed&, strng$, srch$)
  5.     IF seed& <= 0 THEN EXIT DO
  6.     x$ = MID$(strng$, seed&, LEN(srch$))
  7.     PRINT "Found: "; x$; " at position:"; seed&
  8.     seed& = LEN(strng$) - seed& + LEN(srch$)
  9.  
  10. FUNCTION instrrev& (seed&, strng$, srch$)
  11. FOR instrrev& = LEN(strng$) - seed& TO 1 STEP -1
  12.     IF MID$(strng$, instrrev&, LEN(srch$)) = srch$ THEN EXIT FOR
  13. IF srch$ = "" THEN instrrev& = 0
  14.  

Pete
« Last Edit: April 10, 2019, 11:11:20 am by Pete »
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline codeguy

  • Forum Regular
  • Posts: 174
    • View Profile
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #36 on: April 09, 2019, 06:26:56 pm »
I personally believe the original purpose was strictly as a coding challenge on a tutoring site. There are so many approaches that agreeing on one is probably going to be difficult if not impossible. I like the string reverse/INSTR() method because it allows using INSTR() entirely unchanged and doesn't require the same exit logic as _INSTRREV(). This can be done without the reversal too, although I haven't yet coded that one. It has something to do with LEN(Some$) - PositionScan& + !. Please pardon my French as my Win XP SP3 virtual machine does exactly as I type :).

FellippeHeitor

  • Guest
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #37 on: April 09, 2019, 06:33:49 pm »
As much as I respect you, Pete, I'll tell you what I've told Steve all day: We have JUST released a new version of QB64 with a feature that's been added 10 months back, overtly talked about in this forum. This not the time to lobby for a change.

The way _INSTRREV works is the way it was designed to work 10 months back. Back then all sorts of discussion and concession would have been easier.

Right now what we have is a stable release being advertised everywhere I can and which works as indicated in the wiki, link in my previous post.

Code: QB64: [Select]
  1. I still lobby for make _INSTRREV() work more like my function
Adjusting your expectations here means accepting that a function that *didn't exist before* now exists and works as it's been explained. And you now have written yourself a nice function for your own use that does exactly what you expect it to. Just like codeguy has been doing for a while now too in this thread.

People will read the wiki and learn how the new feature works. And they'll either use it or not. We have features galore and not everyone uses all of them.

Can we please celebrate a new release and cut back on the clippiness?
« Last Edit: April 09, 2019, 06:38:37 pm by FellippeHeitor »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #38 on: April 09, 2019, 06:38:52 pm »
If there is a simpler way. I'm all ears, but this it what I came up with for now...

Here's you a nice and simple way to fix things, Pete:

Code: QB64: [Select]
  1. 'we use console so we can see the output of any shell which is going on.
  2. _TITLE "_INSTR Fix Runtime"
  3.  
  4. CHDIR "internal\c\"
  5.  
  6. OPEN "libqb.cpp" FOR INPUT AS #1
  7. OPEN "libqb.tmp" FOR OUTPUT AS #2
  8.     LINE INPUT #1, temp$
  9.     IF INSTR(temp$, "int32 func__instrrev(int32 start,qbs *str,qbs *substr,int32 passed)") THEN SetFlag = -1
  10.     IF SetFlag THEN 'we're down at the proper function to change
  11.         IF INSTR(temp$, "if (start<1){") THEN 'we found the line to change.
  12.             PRINT #2, "    if (start<0){"
  13.             PRINT "Fix applied."
  14.             SetFlag = 0
  15.             SetFlag2 = -1
  16.         ELSE
  17.             PRINT #2, temp$
  18.         END IF
  19.         IF INSTR(temp$, "void sub_mid") THEN SetFlag = 0 'make certain we don't change anything else, in case the file was previously altered.
  20.     ELSE
  21.         PRINT #2, temp$
  22.     END IF
  23.  
  24. IF SetFlag2 THEN
  25.  
  26.     KILL "libqb.cpp"
  27.     NAME "libqb.tmp" AS "libqb.cpp"
  28.  
  29.     SHELL "purge_libqb_only.bat"
  30.     KILL "libqb.tmp" 'delete the duplicate we made of the file, as it's basically an exact copy of libqb.cpp.
  31.     PRINT "Changes not made.  You may have already ran the patch, or else the QB64 source has been fixed itself."

Run that patch from QB64 and it'll correct the issue once and for all for you.  It makes the very simple, 1 line change, which is needed to have QB64 behave as you'd expect it to with _INSTRREV.  There's no need to make your own function, or jump through hoops to have it work properly -- just run that little patch routine. 

Once you do, all you have to do is run a very simple little set of code like the following and watch it work properly:
Code: QB64: [Select]
  1.     seed = _INSTRREV(seed - 1, "1111", "1")
  2.     PRINT seed
  3.     SLEEP
  4. LOOP UNTIL seed = 0

The above will print out:
4
3
2
1
0

And then, quit.

No endless loop, as 0 is no longer a magic number to make it automatically start searching from the end of the string.  It works as you'd expect..
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

FellippeHeitor

  • Guest
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #39 on: April 09, 2019, 06:54:41 pm »
Then run that on everyone else's computer. Or don't ever share code.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #40 on: April 09, 2019, 07:10:14 pm »
Then run that on everyone else's computer. Or don't ever share code.

Why?  How many times have you had to use that one particular command with QB64, in the last 10 months?  Would the patch make it so you couldn't *ever* share code?

If Pete patches his version of QB64, and shares code which doesn't work for anyone else, all that's needed is for him to either say:

1) Download a fresh version of QB64.  Install it in a separate folder, and run the patch for yourself, and have it run as expected.

OR

2) You'll need to modify it so that it works as intended on your system.

We see messages based on principle 2 all the time -- like with my Wallpaper Changer.  Folks have to change the directory to wherever their photos/screenshots are stored, and it won't work on Linux/Mac machines at all.  As long as Pete realizes that any code he shares which makes use of the patched _INSTRREV may not work on everybody else's machine, that's all he needs to disclose when sharing code elsewhere for others. 

Folks who *do* use the patch can freely make use of the code he shares which uses the _INSTRREV.  Those who don't use the patch are simply like users who run a Linux system and you share code which uses a declared Windows library.  All they'd say is, "Doesn't work for me and my system."
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

FellippeHeitor

  • Guest
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #41 on: April 09, 2019, 07:13:05 pm »
Of course, nothing to stop anyone.

It's an open source project after all. It's not even mine.

That also gets me thinking, why didn't you patch the repo yet? What's stopping you if everyone is for the change of the new command?

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #42 on: April 09, 2019, 07:24:27 pm »
Of course, nothing to stop anyone.

It's an open source project after all. It's not even mine.

That also gets me thinking, why didn't you patch the repo yet? What's stopping you if everyone is for the change of the new command?

Because there's nothing to stop you from reverting the changes back out.  You're 100% against the change as "it's too late to speak up and alter anything now", and I ran through hoops with Clippy undoing changes everything I corrected something in the wiki.  If you're convinced it's working as it should, then there's no reason for me to "introduce a bug" into it and make it work any differently than the documentation in the wiki and help files now.

Those who think it's broken can run the patch provided, much like they can run the autobackup and autoreplace scripts which I wrote to alter the behavior of QB64.  Those who like it as it is, or who don't think it's worth the bother, they can simply leave alone and not bother with any alterations.

Hopefully, after you run the patch and test it out for yourself, you'll see that it's how QB64 should behave, and then you'll be happy with the alteration, without feeling a need to undo them, or thinking that ithe patch makes it a broken command.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

FellippeHeitor

  • Guest
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #43 on: April 09, 2019, 07:26:12 pm »
Code: QB64: [Select]
  1. that it's how QB64 should behave

Just precious.

Offline Raven_Singularity

  • Forum Regular
  • Posts: 158
    • View Profile
Re: Seed parameter in the new _INSTRREV() statement.
« Reply #44 on: April 09, 2019, 07:58:32 pm »
I have never used _INSTR() or INSTREV() before, but if this is an issue of consistency, I would highly recommend going for consistency in the functions, even if it means some current programs will break as a result.

After a decade of using PHP, I can say by far the worst part of it for me is the entirely inconsistent functions!  Some function names have the modifier at the end, some at the start.  Functions that are mirrors of each other have parameters in the opposite order, etc.  It's a giant ugly mess, and makes it far harder to learn the programming language than it needs to be.  If you have "foo_on()" you should have "foo_off()" not "disable_foo()".  Programmers in general have a focus to details and consistency, as is needed to be good at programming.  Functions that don't operate as expected, or are not named as expected, are a burden.  It takes you out of programming logic, instead forcing you to focus on remembering the inconsistencies.


The descriptions read:

Quote
The INSTR function searches for the first occurence of a search STRING within a base string and returns the position it was found.

position% = INSTR([start%,] baseString$, searchString$)

 -and-

Quote
The _INSTRREV function searches for a substring inside another string, but unlike INSTR it searches from right to left.

position% = _INSTRREV([start%,] baseString$, subString$)


These don't behave the same?

Because their descriptions say they do, and the function name with REV at the end indicates it is the same but reversed.