QB64.org Forum

Active Forums => QB64 Discussion => Topic started by: Pete on April 08, 2019, 03:25:17 pm

Title: Seed parameter in the new _INSTRREV() statement.
Post by: Pete on April 08, 2019, 03:25:17 pm
I don't think the first parameter of the new _INSTRREV() works. That would be the seed variable.

Code: QB64: [Select]
  1. strng$ = "*,@,h,&,h,a,b,c,d,e,f,g,h,1,2,h"
  2. srch$ = "h"
  3. seed& = 2
  4. PRINT instrrev&(seed&, strng$, srch$) ' My function returns 25, the position of the next h, from the end, less 2-characters in.
  5. PRINT _INSTRREV(2, strng$, "h") 'This should not be a zero.
  6.  
  7. FUNCTION instrrev& (seed&, strng$, srch$)6
  8.     b$ = SPACE$(LEN(strng$))
  9.     FOR i& = LEN(b$) TO 1 STEP -1
  10.         j& = j& + 1
  11.         MID$(b$, j&, 1) = MID$(strng$, i&, 1)
  12.     NEXT
  13.     instrrev& = LEN(b$) - INSTR(seed&, b$, srch$) + 1

So if you don't seed it, and just use, PRINT _INSTRREV(strng$, "h"), it will return 31, which is the location of the h at the end, but if you seed it to, PRINT _INSTRREV(2, strng$, "h"), it just returns a zero. In other words, if it is going 2-characters in from the end, it should ignore the h on the end, which it does, but it should find the next h from the end, which it doesn't.

Pete

Title: Re: I think the seed parameter in the new _INSTRREV() doesn't work.
Post by: Petr on April 08, 2019, 03:45:06 pm
Hi. I think the number two is the position from the beginning of the string and then it would be fine.
Title: Re: I think the seed parameter in the new _INSTRREV() doesn't work.
Post by: Petr on April 08, 2019, 03:55:35 pm
When you enter position 9, it search from the ninth position toward the beginning and returns 8, and that's ok.
Title: Re: I think the seed parameter in the new _INSTRREV() doesn't work.
Post by: Pete on April 08, 2019, 03:55:43 pm
Hi. I think the number two is the position from the beginning of the string and then it would be fine.

You're right. I tried, PRINT _INSTRREV(7, strng$, "h"), and it displayed position 5, the position of the last h, 7 or less characters in. It just seems weird to use it that way.

Pete
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: Pete on April 08, 2019, 04:15:23 pm
I modified the message title. Since this is not in the wiki, maybe others will reference this topic, if needed.

Anyway, I just have to change my mirror image mindset and just make the seed variable the length of the string, to start, and progressively subtract. No biggie.

Pete
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: bplus on April 08, 2019, 04:22:49 pm
Another example:
Code: QB64: [Select]
  1. _TITLE "INSTRREV test" 'B+ 2019-04-08
  2.  
  3. s$ = "one two three four five six seven eight nine ten"
  4. find = _INSTRREV(LEN(s$), s$, " ")
  5. WHILE find > 0
  6.     'PRINT LEFT$(s$, find - 1)
  7.     PRINT MID$(s$, find + 1)
  8.     find = _INSTRREV(find - 1, s$, " ")
  9.  

EDIT: liked the slippery slope version better
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill on April 08, 2019, 04:29:42 pm
Something here seems off to me as well.

Here's a standard loop where we'd see where the "1" appears in "1111":

Code: QB64: [Select]
  1.     seed = INSTR(seed + 1, "1111", "1")
  2.     PRINT seed
  3. LOOP UNTIL seed = 0

Now, if we want to do the same with _INSTRREV, we end up with a problem:

Code: QB64: [Select]
  1. seed = LEN("1111") + 1
  2.     seed = _INSTRREV(seed - 1, "1111", "1")
  3.     PRINT seed
  4.     SLEEP
  5. LOOP UNTIL seed = 0

With _INSTRREV, the seed is currently the number from the left, so when we do _INSTRREV(3, "abcdef", whatever$), what we're looking for is where whatever$ appears in "abc".  With _INSTRREV(2, "abcdef", whatever$), what we're looking for is where whatever$ appears in "ab".

But when the seed becomes 0, what we look for is where whatever$ appears in "abcdef"...

If seed represents basically working with LEFT$(search$,seed), then a seed of 0 should always return "" instead of the search$.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill on April 08, 2019, 04:32:36 pm
Another example:
Code: QB64: [Select]
  1. _TITLE "INSTRREV test" 'B+ 2019-04-08
  2.  
  3. s$ = "one two three four five six seven eight nine ten"
  4. find = _INSTRREV(LEN(s$), s$, " ")
  5. WHILE find > 0
  6.     'PRINT LEFT$(s$, find - 1)
  7.     PRINT MID$(s$, find + 1)
  8.     find = _INSTRREV(find - 1, s$, " ")
  9.  

EDIT: liked the slippery slope version better

To also illustrate the isue, let's use Bplus's code with an extra space at the front of the string:

Code: QB64: [Select]
  1. _TITLE "INSTRREV test" 'B+ 2019-04-08
  2.  
  3. s$ = " one two three four five six seven eight nine ten"
  4. find = _INSTRREV(LEN(s$), s$, " ")
  5. WHILE find > 0
  6.     'PRINT LEFT$(s$, find - 1)
  7.     PRINT MID$(s$, find + 1), find
  8.     find = _INSTRREV(find - 1, s$, " ")
  9.  
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: bplus on April 08, 2019, 04:37:57 pm
Oh my poor befuddled code!
Code: QB64: [Select]
  1. _TITLE "INSTRREV test" 'B+ 2019-04-08
  2.  
  3. 'big problem if the s$ starts with a space!!! as pointed out by Steve.
  4.  
  5. s$ = "   one two three four five six seven eight nine ten"
  6. find = _INSTRREV(LEN(s$), s$, " ")
  7. WHILE find > 0
  8.     'PRINT LEFT$(s$, find - 1)
  9.     PRINT MID$(s$, find + 1), find
  10.     IF find > 1 THEN find = _INSTRREV(find - 1, s$, " ") ELSE EXIT WHILE
  11.  
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill on April 08, 2019, 05:06:13 pm
Fix to this issue is rather simple:

In libqb.cpp, go in and find the func_instrrev.  Change the following:
Code: QB64: [Select]
  1.     if (start<1){
  2.         start=str->len-substr->len+1;
  3.     }

To:

Code: QB64: [Select]
  1. if (start<substr->len) return 0;

Is the seed is less than 1, we don't want to compare against the whole of the string.  We simply want to say there's no substring inside the searchstring.



Unless there's some odd and unfathomable (to me, at the moment, at least) reason for it to behave as it currently is, I can easily push the changes into the repo and correct this minor issue, if you guys want.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: FellippeHeitor on April 08, 2019, 05:12:44 pm
I'd like you gentlemen to please adjust your expectations. Especially considering that the wiki article is still being written, as pointed out above.

With the exception of the last case stated in the list contained in https://www.techonthenet.com/excel/formulas/instrrev.php (https://www.techonthenet.com/excel/formulas/instrrev.php) (under the header "Example (as VBA Function)"), the behavior of the new function is expected to be as described in the link I now share. And it is.

Fellippe.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill on April 08, 2019, 05:23:23 pm
I'd like you gentlemen to please adjust your expectations. Especially considering that the wiki article is still being written, as pointed out above.

With the exception of the last case stated in the list contained in https://www.techonthenet.com/excel/formulas/instrrev.php (https://www.techonthenet.com/excel/formulas/instrrev.php) (under the header "Example (as VBA Function)"), the behavior of the new function is expected to work as described in the link I now share.

Fellippe.

I honestly think the change I just posted before you, is the one you're wanting so that it behaves as indicated.

What you currently have is:

Code: QB64: [Select]
  1.    if (start<1){
  2.         start=str->len-substr->len+1;
  3.     }

Which basically translates down to:

IF start < 1 THEN
  start = LEN(mainstring$) - LEN(searchstring$) + 1
END IF

Let's say I have a search string of "1234567890abc".

If I'm looking for "abc" in the -3rd position of that string, I should either:
1) Get an error as there is no -3rd position of that string.
2) Get a return value of 0, as there is no -3rd position of that string.

I certainly don't think I should get a value of 11 by searching left from the -3rd position... 
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: FellippeHeitor on April 08, 2019, 05:31:09 pm
In the link I just shared there's a use for a negative value (-1 specifically, but I didn't bother not generalize). I'll let you have a look first.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill on April 08, 2019, 05:35:00 pm
In the link I just shared there's a use for a negative value (-1 specifically, but I didn't bother not generalize). I'll let you have a look first.

I saw it.  I just don't think you really want it.

As the command exists currently, fix this so that it properly terminates as intended for us:
Code: QB64: [Select]
  1. seed = LEN("1111") + 1
  2.     seed = _INSTRREV(seed - 1, "1111", "1")
  3.     PRINT seed
  4.     SLEEP
  5. LOOP UNTIL seed = 0

With a seed of 0, or less, we need to terminate search; not go back to the beginning of the string and start over again.



To compare behavior, take a run of this little set of code:

Code: QB64: [Select]
  1. PRINT INSTR(11, "1234567890", "1")
  2. PRINT _INSTRREV(-1, "1234567890", "1")

There's no "1" from the 11th position of our "1234567890" to the right of it.  The result is 0.
Yet, we found a "1" somewhere to the left of our -1st position of that string?

Shouldn't both of these functions return the same value, if a substring only exists once inside the searchstring?
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: FellippeHeitor on April 08, 2019, 06:32:12 pm
I understand that the name may give the idea these functions should be mere mirrors of each other and although at some points they are, the mindset here is different. With that in mind, I repeat: it's a matter of adjusting your expectations. The function behaves as intended.

Code: QB64: [Select]
  1.     seed = _INSTRREV(seed - 1, "1111", "1")
  2.     PRINT seed
  3. LOOP UNTIL seed = 0 OR seed = 1
  4. IF seed = 0 THEN PRINT "substring not found"
  5. IF seed = 1 THEN PRINT "substring found at beginning of main string; search interrupted"
  6.  
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: FellippeHeitor on April 08, 2019, 06:33:56 pm
Also notice how it's useful to start at -1 so you don't have to bother with the length of the string. Again, as intended.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill on April 08, 2019, 06:39:06 pm
Ah well.  I never needed the command in the past.  As it is, I doubt I’ll ever use it in the future either.  All to their own.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: Pete on April 08, 2019, 10:10:32 pm
Well, I tested it out with one of the forum index searches a few of us did a couple of months back. It worked fine for this particular application, but...

Code: QB64: [Select]
  1. s$ = ",bill,cat,dog,dogfood,pete,steve,bill,cat,dog,dogfood,pete,steve,bill,cat,dog,dogfood,pete,steve,"
  2. PRINT "INSTR - Forward!"
  3.     seed& = INSTR(seed&, s$, ",dog,")
  4.     IF seed& = 0 THEN EXIT DO
  5.     x$ = MID$(s$, seed& + 1, LEN("dog"))
  6.     PRINT x$, seed&
  7.     seed& = seed& + LEN(",dog,")
  8. PRINT "_INSTRREV - Reverse!"
  9.     seed& = _INSTRREV(seed&, s$, ",dog,")
  10.     IF seed& = 0 THEN EXIT DO
  11.     x$ = MID$(s$, seed& + 1, LEN("dog"))
  12.     PRINT x$, seed&
  13.     seed& = seed& - LEN(",dog,")

If we add ,dog, as the first entry, it does that endless loop situation Steve brought up. That really needs to be changed.

Code: QB64: [Select]
  1. s$ = ",dog,bill,cat,dog,dogfood,pete,steve,bill,cat,dog,dogfood,pete,steve,bill,cat,dog,dogfood,pete,steve,dog,"
  2. PRINT "INSTR - Forward!"
  3.     seed& = INSTR(seed&, s$, ",dog,")
  4.     IF seed& = 0 THEN EXIT DO
  5.     x$ = MID$(s$, seed& + 1, LEN("dog"))
  6.     PRINT x$, seed&
  7.     seed& = seed& + LEN(",dog,")
  8. PRINT "_INSTRREV - Reverse!"
  9.     seed& = _INSTRREV(seed&, s$, ",dog,")
  10.     IF seed& = 0 THEN EXIT DO
  11.     x$ = MID$(s$, seed& + 1, LEN("dog"))
  12.     PRINT x$, seed&: SLEEP
  13.     seed& = seed& - LEN(",dog,")
  14.  

I put a SLEEP statement in the _INSTRREV, so you can step through it rather than watch it repeat like crazy across the screen.

I added a ,dog, to the end of the string, too; however, this has no adverse effect. So only adding it at the beginning causes an issue of repeat looping.

Pete
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: FellippeHeitor on April 08, 2019, 10:12:45 pm
The result of _INSTRREV will only ever be zero if the substring is *not* there. Please check the article, explanation and code I shared above.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: FellippeHeitor on April 08, 2019, 10:21:09 pm
Also, check if the result is = 1 TO determine the end of search, as I showed in my snippet.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: Pete on April 08, 2019, 11:28:47 pm
Or Steve, just because some $#$%^$$ in VBA made it that way, means we need to follow? QB compatible I get, but VBA compatible? Come on guys, that's bullscript in my ledger. Besides, VBA puts the damn seed as the third parameter.

Anyway, much like Steve I see having the function with an escape plan more efficient and elegant than what I had to quickly come up with to exit this QB64 VBA statement clone...

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. PRINT "QB64's instrrev with Pete's escape method added..."
  4.     seed& = _INSTRREV(seed&, strng$, ",dog,")
  5.     IF seed& = 0 OR seed& > lastseed& AND lastseed& <> 0 THEN EXIT DO '  OR Needed to escape looping if string begins with search term.
  6.     x$ = MID$(strng$, seed& + 1, LEN("dog"))
  7.     PRINT x$, seed&
  8.     seed& = seed& - LEN(",dog,")
  9.     lastseed& = seed& ' Needed to escape looping if string begins with search term.
  10. PRINT "Pete's instrrev function with SMART escape...": seed& = 0
  11.     seed& = instrrev&(seed&, strng$, srch$)
  12.     IF seed& = 0 THEN EXIT DO
  13.     x$ = MID$(strng$, seed& + 1, LEN("dog"))
  14.     PRINT x$, seed&
  15.     seed& = LEN(strng$) - seed& + LEN(",dog,") - 1
  16.  
  17. FUNCTION instrrev& (seed&, strng$, srch$)
  18. b$ = SPACE$(LEN(strng$))
  19. srchx$ = SPACE$(LEN(srch$))
  20. FOR i& = LEN(srchx$) TO 1 STEP -1
  21.     j& = j& + 1
  22.     MID$(srchx$, j&, 1) = MID$(srch$, i&, 1)
  23. j& = 0
  24. FOR i& = LEN(b$) TO 1 STEP -1
  25.     j& = j& + 1
  26.     MID$(b$, j&, 1) = MID$(strng$, i&, 1)
  27. instrrev& = LEN(b$) + 1 - (INSTR(seed&, b$, srchx$) + LEN(srchx$) - 1)
  28. IF INSTR(seed&, b$, srchx$) = 0 THEN instrrev& = 0 ' It will now exit if asked.
  29.  

I will read that article tomorrow, sorry I could not get to it before coding this and a few other things.

Pete
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: bplus on April 08, 2019, 11:47:21 pm
This is like modulus for strings:
Code: QB64: [Select]
  1. _TITLE "INSTRREV test" 'B+ 2019-04-09 reminds me of modulus
  2.  
  3. s$ = " one two three four five six seven eight nine ten"
  4. lastFind = LEN(s$) + 1
  5. find = _INSTRREV(LEN(s$), s$, " ")
  6. n = 10
  7. WHILE find > 0
  8.     n = (n - 1) MOD 10
  9.     IF n < 0 THEN n = 9
  10.     PRINT n + 1,
  11.     PRINT MID$(s$, find + 1, lastFind - find - 1)
  12.     INPUT "OK... enter"; wate$
  13.     ' lastFind = find <<<don't need his line
  14.     IF find = 1 THEN lastFind = LEN(s$) + 1 ELSE lastFind = find
  15.     find = _INSTRREV(find - 1, s$, " ")
  16.  
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill on April 09, 2019, 03:29:22 am
And. since Fell wants to say that we need to be compatible with other languages with this one, perhaps he should take a moment to look at how .NET actually implements it: https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.strings.instrrev?redirectedfrom=MSDN&view=netframework-4.7.2#Microsoft_VisualBasic_Strings_InStrRev_System_String_System_String_System_Int32_Microsoft_VisualBasic_CompareMethod_

Let's take a close look at the RETURNS section:

If...... Start is greater than length of StringMatch   ....InStrRev returns.... 0.

Which is the exception I was trying to add into the command...

Also, let's take a close look at the ARGUMENT EXCEPTIONS:

ArgumentException:  Start = 0 or Start < -1.

So, as I mentioned in my previous post, you can have -1 be a shortcut to use the length of the whole search string, but 0 as a seed should return a value of 0.  It's too bad we're stuck with it being a feature the way it is now, rather than admitting it's a bug which would be rather simple to correct...

   
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: codeguy on April 09, 2019, 03:49:38 am
Code: QB64: [Select]
  1. my$ = "tom jane fred lois dog cat mouse tom jerry mouse"
  2. t& = LEN(my$)
  3.     t& = InStringReverse&(t&, my$, "tom")
  4.     PRINT t&
  5.     IF t& > 0 THEN
  6.         t& = t& - LEN("tom")
  7.     ELSE
  8.         EXIT DO
  9.     END IF
  10. LOOP WHILE t& > 0
  11.  
  12. FUNCTION InStringReverse& (start&, x$, f$)
  13.     ps& = start& - LEN(f$) + 1
  14.     IF ps& > 0 THEN
  15.         DO
  16.             IF ps& > 0 THEN
  17.                 IF MID$(x$, ps&, LEN(f$)) = f$ THEN
  18.                     EXIT DO
  19.                 ELSE
  20.                     ps& = ps& - 1
  21.                 END IF
  22.             ELSE
  23.                 EXIT DO
  24.             END IF
  25.         LOOP
  26.     END IF
  27.     InStringReverse& = ps&
  28.  
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill on April 09, 2019, 04:08:57 am
Code: QB64: [Select]
  1. my$ = "tom jane fred lois dog cat mouse tom jerry mouse"
  2. t& = LEN(my$)
  3.     t& = InStringReverse&(t&, my$, "tom")
  4.     PRINT t&
  5.     IF t& > 0 THEN
  6.         t& = t& - LEN("tom")
  7.     ELSE
  8.         EXIT DO
  9.     END IF
  10. LOOP WHILE t& > 0
  11.  
  12. FUNCTION InStringReverse& (start&, x$, f$)
  13.     ps& = start& - LEN(f$) + 1
  14.     IF ps& > 0 THEN
  15.         DO
  16.             IF ps& > 0 THEN
  17.                 IF MID$(x$, ps&, LEN(f$)) = f$ THEN
  18.                     EXIT DO
  19.                 ELSE
  20.                     ps& = ps& - 1
  21.                 END IF
  22.             ELSE
  23.                 EXIT DO
  24.             END IF
  25.         LOOP
  26.     END IF
  27.     InStringReverse& = ps&
  28.  

That's basically how it should behave, codeguy, with one minor change:

Code: QB64: [Select]
  1. my$ = "tom jane fred lois dog cat mouse tom jerry mouse"
  2. t& = -1
  3.     t& = InStringReverse&(t&, my$, "tom")
  4.     PRINT t&
  5.     IF t& > 0 THEN
  6.         t& = t& - LEN("tom")
  7.     ELSE
  8.         EXIT DO
  9.     END IF
  10. LOOP WHILE t& > 0
  11.  
  12. FUNCTION InStringReverse& (start&, x$, f$)
  13.     IF start& = -1 THEN start& = LEN(x$)
  14.     ps& = start& - LEN(f$) + 1
  15.     IF ps& > 0 THEN
  16.         DO
  17.             IF ps& > 0 THEN
  18.                 IF MID$(x$, ps&, LEN(f$)) = f$ THEN
  19.                     EXIT DO
  20.                 ELSE
  21.                     ps& = ps& - 1
  22.                 END IF
  23.             ELSE
  24.                 EXIT DO
  25.             END IF
  26.         LOOP
  27.     END IF
  28.     InStringReverse& = ps&
  29.  

IF start& = -1 THEN start& = LEN(x$) is a shortcut so you don't have to manually type LEN(my$) to start a search at the end of the string.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: TempodiBasic on April 09, 2019, 05:53:55 am
Hi guys
fine to learn the existence of this function from you , among the tons of other news in QB64.

before to say a silly thing I try to resume that I have understood from your talking about the right value returned by _INSTRREV when there is a problem with parameters...
1. _INSTRREV is not the simmetrical opposite of INSTR

syntax
_INSTRREV (WheretoSearch$, WhattoSearch$, UntilLastRightCharacterConsidered%,CompareMethod%)
                              ^                          ^                         ^                                                          ^
                              |                            |                          |                                                            |   Who is it?
 string in which we search                  |                          |                                                                  is there In QB64 version of the function?
                                      string to search                        |                                                           
                                                                   Start is a BAD name for this parameter because in this function it shows the last right character of the string to consider in the searching task, but it is right the first character used because the searching comes from right to left (in this sense we can call it START)  but we always read the string from left to right and count the position from the left to right!

To be simmetrical (Reverse INSTR) it would count from the start position ie from the last right character considered going to the left. But this is not the issue.

So _INSTRREV  searches a string1 into a string2 starting from the right side of the string2 less the start position, going to left . The result is the position of string1 counting from the left side of string2.
If start is omitted it is -1 by default and the seaching starts from the last right character of string2.

Here my questions
1. the parameter Compare% is implemented in QB64 _INSTRREV?
2. What have I missed to understand only half of the example that is here https://www.techonthenet.com/excel/formulas/instrrev.php (https://www.techonthenet.com/excel/formulas/instrrev.php)  ?
3. what is the difference between Start = 0, Start = null and Start omitted in QB64?
Quote
If start is null, the INSTRREV function will return #Error.
4. why INSTRREV must return 0 if Start is greater StringMatch ?
Quote
StringMatch
String
Required. String expression being searched for.

Start
Int32
Optional. Numeric expression setting the one-based starting position for each search, starting from the left side of the string. If Start is omitted then -1 is used, meaning the search begins at the last character position. Search then proceeds from right to left.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: TempodiBasic on April 09, 2019, 06:00:07 am
this code confirms the result of this page https://www.techonthenet.com/excel/formulas/instrrev.php (https://www.techonthenet.com/excel/formulas/instrrev.php)
Code: QB64: [Select]
  1. string1 = "alphabet"
  2. string2 = "a"
  3.  
  4. PRINT _INSTRREV(string1, string2)
  5. FOR a = 1 TO 9 STEP 1
  6.  
  7.     PRINT _INSTRREV(a, string1, string2)

Sorry for previous syntax I have written looking at syntax showed here https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.strings.instrrev?redirectedfrom=MSDN&view=netframework-4.7.2#Microsoft_VisualBasic_Strings_InStrRev_System_String_System_String_System_Int32_Microsoft_VisualBasic_CompareMethod_ (https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.strings.instrrev?redirectedfrom=MSDN&view=netframework-4.7.2#Microsoft_VisualBasic_Strings_InStrRev_System_String_System_String_System_Int32_Microsoft_VisualBasic_CompareMethod_)
and here
https://www.techonthenet.com/excel/formulas/instrrev.php (https://www.techonthenet.com/excel/formulas/instrrev.php)

then try to code to use _INSTRREV i have learned from your examples posted that in QB64 synthax comes first Start parameter and then the StringInWhichSearch and following StringToSearch.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: FellippeHeitor on April 09, 2019, 06:08:50 am
Off-topic discussion that was taking place in this thread has been moved to https://www.qb64.org/forum/index.php?topic=1233.msg104360#msg104360
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill on April 09, 2019, 06:11:13 am
Quote
Here my questions
1. the parameter Compare% is implemented in QB64 _INSTRREV?
2. What have I missed to understand only half of the example that is here https://www.techonthenet.com/excel/formulas/instrrev.php  ?
3. what is the difference between Start = 0, Start = null and Start omitted in QB64?
Quote
If start is null, the INSTRREV function will return #Error.
4. why INSTRREV must return 0 if Start is greater StringMatch ?

1.  Nope.  We don’t offer the binary compare method; it wasn’t implemented.

2.  I dunno what you missed.  ;)

3.  If start is omitted, it defaults to the length of the string to be searched.  QB64 does the same, currently, if start = 0, though .NET tosses an error as they use 1 as the terminating value. I don’t think you can pass start a nul in QB64.

4.  I actually think that’s a typo on Microsoft’s page (unless it does so to keep the user from trying to read beyond the length of memory allocated for the string.)  i’m thinking it should read “if start is les than length of StringMatch”.   After all, you can’t find a 7 letter search string in a 3 letter word.  If your start = 3 and len(searchstring) > 3, it should always return 0.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: TempodiBasic on April 09, 2019, 08:43:06 am
Hi Steve
thanks for your time and energy

your answers are clear and logic and I have miss my mind :-), I think that my bug knownledge is about how Start works into the function
Quote
_INSTRREV (Start%, WheretoSearch$, WhattoSearch$ )
if WheretoSearch$ Is "  a l p h a b e t " and Start% = 1

question:
A)
  a l p h a b e t
                     ^
                      |
              is  Start  here if it is equal 1 ?

B)
                     a l p h a b e t
                     ^
                      |
        is  Start  here if it is equal 1 ?


C) Start moves toward left or right?

Thanks
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill 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.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: codeguy 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.  
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: Pete 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
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: FellippeHeitor on April 09, 2019, 05:04:31 pm
http://qb64.org/wiki/INSTRREV (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
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: codeguy 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.  
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: Pete 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
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: codeguy 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 :).
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: FellippeHeitor 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?
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill 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..
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: FellippeHeitor on April 09, 2019, 06:54:41 pm
Then run that on everyone else's computer. Or don't ever share code.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill 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."
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: FellippeHeitor 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?
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill 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.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: FellippeHeitor on April 09, 2019, 07:26:12 pm
Code: QB64: [Select]
  1. that it's how QB64 should behave

Just precious.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: Raven_Singularity 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.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: codeguy on April 09, 2019, 08:27:11 pm
I am going to lightly campaign for this function to mostly mirror INSTR() in returning a value of 0...lengthofstring-lengthofsearchstring+1 in the next STABLE release and leave it as is until then. This behavior would keep it in line with the predictable INSTR(), which never returns a negative result and doesn't conflict with the construct people including me use with INSTR (ie: WHILE INSTR(startpos&, some$, find$). Perhaps starting with 0 as a seed value could indicate the WHOLE string is to be searched and if it returns a 0, the string to find is not contained in the string to be searched, the very same as INSTR(). JM2C (just my 2 cents). I don't think there's any need to get in arguments, just agree on a position SOMEWHERE between that won't completely wreck things.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: SMcNeill on April 09, 2019, 10:11:26 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:

 -and-


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.

They don’t behave the same, currently.

This is the current INSTR:
Code: QB64: [Select]
  1.     seed = _INSTR(seed + 1, “AAAA”, “A”)
  2.     PRINT seed
  3. LOOP UNTIL seed = 0
  4.  

And,this is currently how you’d do that with _INSTRREV:
Code: QB64: [Select]
  1. seed = LEN(“AAAA”) + 1
  2.     seed = _INSTRREV(seed - 1, “AAAA”, “A”)
  3.     PRINT seed
  4. LOOP UNTIL seed = 0 OR seed = 1

Notice how INSTR terminates with a 0?  That basically means, “No more “A” in the string we’re searching.”

_INSTRREV requires you to check for both 0 and 1 values.  0 says, “Nope.  No more “A” found in the string”, but you ALSO have to check for that 1, so you know you’re at the end of the string to search

The change I propose is rather simple, and shouldn’t break any existing code:  Fix _INSTRREV so that it stops checking at the 0th byte of a string, rather than starting back over from the right side again.  All we need to know is “0 means no more search strings found”.   WTH do we need to complicate the process with multiple checks for “am I at the last position in the string”, and “is there no more search strings found”?

_INSTRREV could easily match INSTR’s functionality with a single line change in libqb.cpp.  Unfortunately, the glitch wasn’t found 10 months ago in the beta versions, so it’s now officially a feature and not a bug.

It’s sad to say, but it seems the choice is to either get used to learning the inconsistencies between the two commands, or patch the issue yourself and have code you share with the patched version be incompatible with the general forum community.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: Pete on April 09, 2019, 11:45:54 pm
Here's a good example why I wish it was mirrored with seeding in the first place. Let's say you have a giant list of records, a million plus, delimited by "|" 4 spaces apart, and you want to find the 3rd record from the end of the data file. Well you would think with a reverse INSTR() keyword, you could just ask for the function to return the 3rd record from the end (12-characters from the right) but a seed of 12 in this non-mirror reverse instr() function will just chop off the string after the 12th character from the LEFT, and get the last record in that chopped string. That will be the 3rd record, as per this example, not the 3rd record from the end. To get that record, you'd have to know how many records in total exists, subtract 3 * 4, and use that as the seed. Sure, it's doable, but to me it seems counterintuitive.

OK, so we can work with seeding from left to right in INSTR() and _INSTRREV(), but it does take some alteration, because one is searching forward while the other is searching from behind. Notice I had to alter the seedr% to the seedf% variable to obtain equal results in the following code example.

Code: QB64: [Select]
  1. WIDTH 80, 43
  2.     s$ = "r1 |r2 |r3 |r4 |r5 |r6 |r7 |r8 |r9 |r10|r11|r12"
  3.     s$ = "|" + s$ + "|" ' Enclose.
  4.     PRINT "         1111111111222222222233333333334444444444"
  5.     PRINT "1234567890123456789012345678901234567890123456789"
  6.     PRINT s$: PRINT
  7.     srch$ = "|": interval% = 4
  8.     INPUT "Get record 1-12"; rec%: PRINT
  9.     seedf% = rec% * interval% - interval% + 1
  10.     seedr% = rec% * interval%
  11.     PRINT MID$(s$, INSTR(seedf%, s$, "|") + 1, interval% - 1); " First record"; seedf%; "spaces in from the left. INSTR() ="; INSTR(seedf%, s$, "|")
  12.     PRINT MID$(s$, _INSTRREV(seedr%, s$, "|") + 1, interval% - 1); " Last record within"; seedr%; "spaces from the left. INSTRREV() ="; _INSTRREV(seedr%, s$, "|")
  13.     PRINT
  14.  

Here is a simple comparison of INSTR() and INSTRREV() with a seeded loop.

Code: QB64: [Select]
  1. s$ = "@#a012a345a67a89"
  2. COLOR 7, 0: PRINT "1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16"
  3. COLOR 14, 0: PRINT "@  #  a  0  1  2  a  3  4  5  a  6  7  a  8  9": COLOR 7, 0
  4. PRINT "INSTR()     _INSTRREV()"
  5. FOR i = 1 TO LEN(s$)
  6.     PRINT i; MID$(s$, INSTR(i, s$, "a"), 2), i; MID$(s$, _INSTRREV(i, s$, "a"), 2)

I've used INSTR() over the years probably more than anyone else on this forum. I've always thought it would be great to have a mirror reverse function, but this just isn't quite it. I'm still trying to figure any advantages vs disadvantages with seeding left to right vs right to left, but the one I really cannot find a reason to support is that looping "feature" we've pointed out some message posts back. I feel it needs a valid reason(s) to exist in terms of effecting a desired coding result. Are there any?

Pete
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: codeguy on April 10, 2019, 01:30:35 am
For not-too-large strings, my String reversed method and the calculation used to produce the result in the actual string works perfectly with INSTR() as-is. I tend to avoid novelties like _INTRREV() because they do not mirror the way INSTR() works as I'd expect and apparently you too. Mine is correct, although it may not be the fastest algorithm on earth to achieve the end goal. I have used INSTR() perhaps second-most of all the members here. Mine is a tried and proven way to achieve exactly what you want to do.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: Pete on April 10, 2019, 01:52:07 am
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?

I appreciate that, and I appreciate all the work that goes into making a new release. This reminds me a bit of the postman who delivered a letter through the proverbial snow, rain, heat and gloom of night and the recipient replied. Hey look ascii-hole, you creased the bottom left corner! Actually, I have a more real life similar experience, of when I would bust my but on my office software, reach a finished version, and my wife would say something to the effect of, "Hey dear, you know would would be great..." followed by a laundry list of functions that would only take another couple of minutes, and by minutes, I mean months, to create. Sigh.... A few days after reentry, I'd cool down and since her ideas were generally good ones, get busy and code some more. So to me, this is all a process.

Anyway, we do have a lot to celebrate and to be thankful for. While others have had their coding rugs ripped out from underneath them, this community has managed to manufacture its own stable foundation and, unlike FB, it's still on sound footing. Sure, member tempers flare on occasion, but that's mostly because people care a lot about the project. I'll take that over apathy, any day.

I have used INSTR() a lot. _INSTRREV() will be great for getting the file name, dotcom name, etc., off a long file path/file name string. That by itself is something to crow about. I'm not sure why you feel removing the looping "feature" would not make it better when it comes to use with seeds. Maybe I'm missing something but if so, what possible good use does keeping that serve? I know you wre working on this for the past 10 months, but I only found that out about a week ago. No one sent me a memo, or on my end, I guess I hadn't paid too much attention to the development thread. So, it's new to me.

You know on the N54 Forum, I used to refer to Steve as my evil twin. Funny thing, I used to tell my wife, nearly 30 years ago, when I pulled some stunt she disapproved of, "Honey, it wasn't me, it was my evil twin, Steve!" That got me out of the dog house every time. Imagine my surprise when that figment of my imagination came to life! I just wish I hadn't built him up so much, because he really gives me a run for my money at times. I'd miss him a bunch if he didn't come around anymore. I actually offered him the QB Forum at one point, but he had other pressing matters, something about a lemonade stand, but I digress. Anyway, I hope the two of you can patch things up between each other as well as you can patch up code in the project, and we can all move forward, together.

Oh, and it's Clipishness, not Clippiness. ;)

Pete     
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: TempodiBasic on April 10, 2019, 09:40:43 am
Hi
Thanks

 @Steve to dissolve my shadow in knowledge... before I have thought that the start, being in reverse, was at the right of string and it move itself toward left!

@Fellippe
for quick wiki of _INSTRREV

Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: Raven_Singularity on April 10, 2019, 12:48:32 pm
Sure, member tempers flare on occasion, but that's mostly because people care a lot about the project. I'll take that over apathy, any day.

Hear, hear!

Apathy destroys good software projects every day.


To be clear, I am not trying to belittle all the programming efforts of the QB64 developers.  I have being programming for 32 years, so I know how much work goes into designing, programming, and debugging an app.  I respect that this function was discussed in development 10 months ago, and made its way into the stable branch of QB64.  That said, I still think it would be a better idea to change these functions to be consistent with each other, for the next major stable release, even if it affects some peoples current QB64 code.
Title: Re: Seed parameter in the new _INSTRREV() statement.
Post by: Pete on April 10, 2019, 03:40:11 pm
I didn't want to leave this thread without posting an example of what I mean by a mirror INSTR() function. Basically such a function would look for the sub-string of the string from right to left (backwards searching) but the seed would also be backwards searching. So a seed of 2 would mean, look in 2 characters from the right, and then find the last sub-string occurrence from that point. Here is an example of such a mirror function:

Code: QB64: [Select]
  1. strng$ = "rec-1 ,rec-2 ,rec-3 ,rec-4 ,rec-5 ,"
  2. srch$ = ","
  3. INPUT "Go in this many characters from the right and search backwards from there: "; seed&
  4. rec& = instrrev&(seed&, strng$, srch$)
  5. x$ = MID$(strng$, rec& - 6, 6)
  6. PRINT "Found: "; RTRIM$(x$); " within"; seed&; "spaces from the right at position:"; rec&
  7.  
  8. FUNCTION instrrev& (seed&, strng$, srch$)
  9. FOR instrrev& = LEN(strng$) + 1 - seed& TO 1 STEP -1
  10.     IF MID$(strng$, instrrev&, LEN(srch$)) = srch$ THEN EXIT FOR
  11. IF srch$ = "" OR instrrev& < 0 THEN instrrev& = 0
  12.