Author Topic: INSTR() and AND...  (Read 2770 times)

0 Members and 1 Guest are viewing this topic.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
INSTR() and AND...
« on: March 27, 2019, 02:59:20 pm »
Or.. Bitwise ladies sing this song doodah, doodah...

It's nice to shortcut statements like IF LEN(k$) instead of using IF mykey$ <> "" but if you want to combine statements with AND, you need to careful. For instance, you can write IF INSTR(x$, k$) THEN instead of IF INSTR(x$, k$) <> 0 THEN but if you combine it with another statement and use AND, you will experience different results.

Code: QB64: [Select]
  1. WIDTH 120, 43
  2. PRINT "The first routine uses AND INSTR(x$, k$) THEN. You'll see 'false' zero, for 2, 4, 6, and 8."
  3. PRINT "The second routine starts after 9 is processed. It uses 'INSTR(x$, k$) <> 0 THEN' All numbers will be processed."
  4. PRINT "DEMO 1 with AND INSTR(x$, k$) THEN": PRINT
  5. x$ = "123456789": LOCATE , , 1, 7, 7
  6.     IF disp% = 0 THEN i = i + 1: PRINT "Press " + LTRIM$(STR$(i)) + ": ";: disp% = -1
  7.     _LIMIT 10
  8.     k$ = INKEY$
  9.     IF LEN(k$) AND INSTR(x$, k$) THEN
  10.         IF k$ = CHR$(27) THEN SYSTEM
  11.         PRINT k$: PRINT "Checkpoint OK: "; "LEN(k$) ="; LEN(k$); "INSTR(x$, k$) ="; INSTR(x$, k$); "LEN(k$) AND INSTR(x$, k$) ="; LEN(k$) AND INSTR(x$, k$): disp% = 0
  12.         disp% = 0
  13.     ELSE
  14.         IF LEN(k$) THEN
  15.             PRINT k$: PRINT "Can't Process: "; "LEN(k$) ="; LEN(k$); "INSTR(x$, k$) ="; INSTR(x$, k$); "LEN(k$) AND INSTR(x$, k$) ="; LEN(k$) AND INSTR(x$, k$): disp% = 0
  16.         END IF
  17.     END IF
  18.     IF k$ = "9" THEN EXIT DO
  19.  
  20. PRINT: PRINT "DEMO 2 with AND INSTR(x$, k$) <> 0 THEN": i = 0: PRINT
  21.     IF disp% = 0 THEN i = i + 1: PRINT "Press " + LTRIM$(STR$(i)) + ": ";: disp% = -1
  22.     _LIMIT 10
  23.     k$ = INKEY$
  24.     IF LEN(k$) AND INSTR(x$, k$) <> 0 THEN
  25.         IF k$ = CHR$(27) THEN SYSTEM
  26.         PRINT k$: PRINT "Checkpoint OK: "; "LEN(k$) ="; LEN(k$); "INSTR(x$, k$) <> 0 ="; INSTR(x$, k$) <> 0; "LEN(k$) AND INSTR(x$, k$) <> 0 ="; LEN(k$) AND INSTR(x$, k$) <> 0: disp% = 0
  27.         disp% = 0
  28.     ELSE
  29.         IF LEN(k$) THEN
  30.             PRINT k$: PRINT "Can't Process: "; "LEN(k$) ="; LEN(k$); "INSTR(x$, k$) <> 0 ="; INSTR(x$, k$) <> 0; "LEN(k$) AND INSTR(x$, k$) <> 0 ="; LEN(k$) AND INSTR(x$, k$) <> 0: disp% = 0
  31.         END IF
  32.     END IF
  33.     IF k$ = "9" THEN EXIT DO
  34.  

This actually 'bit' me in the ASCII a few years ago. I was wondering why what I knew was a true INSTR() result wasn't being processed correctly. When i noticed I had it in a combined conditional statement, I just added the > 0 part, and of course it worked fine. I just thought I'd share this experience here.

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: INSTR() and AND...
« Reply #1 on: March 28, 2019, 12:31:28 am »
This is explained by AND simply *NOT* being a logical operator in QB64; it's a binary operation.

Try these simple commands:

PRINT 1 AND 3
PRINT 1 AND 2
PRINT 2 AND 3

The results are:
1
0
2

And how does this relate to your coding example, you ask?

If k$ = "2", and x$ = "123456789", then INSTR$(x$,k$) is going to equal 2 -- it's in the second position of the search string...

Now, since k$ = "2", the LEN(k$) = 1...

And your IF condition test is:

IF LEN(k$) AND INSTR(x$, k$) THEN 

Which processes as:

IF 1 AND 2 THEN...

And, as we saw above, 1 AND 2 are 0 -- which is what QB64 considers to be a FALSE logical value.



You're using BINARY OPERATIONS and expecting LOGIC-BASED RESULTS -- and as you noticed in your code, that's *NOT* going to work properly for you.

The solution is, as you have already noticed, to transform that AND so that you're comparing logic values (TRUE/FALSE) instead of binary numbers.

INSTR(x$, k$) <> 0 can ONLY give you logic values -- 0 for False, -1 for True.
LEN(k$) <> 0 can ONLY give you logic values -- 0 for False, -1 for True.

You can swap out *EITHER* of those binary numbers to make them logical values, and the program will them work as you intend -- the glitch isn't just something in INSTR()...

For example:

Code: QB64: [Select]
  1. WIDTH 120, 43
  2. PRINT "The first routine uses AND INSTR(x$, k$) THEN. You'll see 'false' zero, for 2, 4, 6, and 8."
  3. PRINT "The second routine starts after 9 is processed. It uses 'INSTR(x$, k$) <> 0 THEN' All numbers will be processed."
  4. PRINT "DEMO 1 with AND INSTR(x$, k$) THEN": PRINT
  5. x$ = "123456789": LOCATE , , 1, 7, 7
  6.     IF disp% = 0 THEN i = i + 1: PRINT "Press " + LTRIM$(STR$(i)) + ": ";: disp% = -1
  7.     _LIMIT 10
  8.     k$ = INKEY$
  9.     IF LEN(k$) AND INSTR(x$, k$) THEN
  10.         IF k$ = CHR$(27) THEN SYSTEM
  11.         PRINT k$: PRINT "Checkpoint OK: "; "LEN(k$) ="; LEN(k$); "INSTR(x$, k$) ="; INSTR(x$, k$); "LEN(k$) AND INSTR(x$, k$) ="; LEN(k$) AND INSTR(x$, k$): disp% = 0
  12.         disp% = 0
  13.     ELSE
  14.         IF LEN(k$) THEN
  15.             PRINT k$: PRINT "Can't Process: "; "LEN(k$) ="; LEN(k$); "INSTR(x$, k$) ="; INSTR(x$, k$); "LEN(k$) AND INSTR(x$, k$) ="; LEN(k$) AND INSTR(x$, k$): disp% = 0
  16.         END IF
  17.     END IF
  18.     IF k$ = "9" THEN EXIT DO
  19.  
  20. PRINT: PRINT "DEMO 2 with AND LEN(k$) <> 0 AND INSTR(x$,k$) THEN": i = 0: PRINT
  21.     IF disp% = 0 THEN i = i + 1: PRINT "Press " + LTRIM$(STR$(i)) + ": ";: disp% = -1
  22.     _LIMIT 10
  23.     k$ = INKEY$
  24.     IF LEN(k$) <> 0 AND INSTR(x$, k$) THEN
  25.         IF k$ = CHR$(27) THEN SYSTEM
  26.         PRINT k$: PRINT "Checkpoint OK: "; "LEN(k$) <> 0 ="; LEN(k$) <> 0; "INSTR(x$, k$) ="; INSTR(x$, k$); "LEN(k$) AND INSTR(x$, k$) <> 0 ="; LEN(k$) <> 0 AND INSTR(x$, k$): disp% = 0
  27.         disp% = 0
  28.     ELSE
  29.         IF LEN(k$) THEN
  30.             PRINT k$: PRINT "Can't Process: "; "LEN(k$) ="; LEN(k$); "INSTR(x$, k$) <> 0 ="; INSTR(x$, k$) <> 0; "LEN(k$) AND INSTR(x$, k$) <> 0 ="; LEN(k$) AND INSTR(x$, k$) <> 0: disp% = 0
  31.         END IF
  32.     END IF
  33.     IF k$ = "9" THEN EXIT DO
  34.  

As another, even simpler, demo of this process in action, take a close look at the code below:

Code: QB64: [Select]
  1. x$ = "2"
  2.  
  3. IF LEN(x$) AND VAL(x$) THEN PRINT "It's good!" ELSE PRINT "NOPE!"
  4. IF LEN(x$) <> 0 AND VAL(x$) THEN PRINT "It's good!" ELSE PRINT "NOPE!"
  5. IF LEN(x$) AND VAL(x$) <> 0 THEN PRINT "It's good!" ELSE PRINT "NOPE!"
  6.  

The LEN(x$) is 1.  The VAL(x$) is 2.
1 AND 2 is 0...  The first comparison is false.
1 <> 0 AND 2 is 2...   (It becomes -1 AND 2, which then becomes 2)... The second comparison is true.
1 AND 2 <> 0 is 1...   (It become 1 AND -1, which then becomes 1)... The third comparison is true.



This isn't a glitch at all with INSTR.  It's simply how AND behaves when used as a binary operator.

If you want to avoid these type of issues, be certain to ONLY use AND when you're comparing TRUE/FALSE type results. 

Either that, or else write yourself a LOGIC_AND and use it for the comparisons:

Code: QB64: [Select]
  1. x$ = "2"
  2.  
  3. IF L_AND(LEN(x$), VAL(x$)) THEN PRINT "It's good!" ELSE PRINT "Nope!"
  4.  
  5. FUNCTION L_AND (val1, val2)
  6.     IF val1 <> 0 AND val2 <> 0 THEN L_AND = -1
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline codeguy

  • Forum Regular
  • Posts: 174
    • View Profile
Re: INSTR() and AND...
« Reply #2 on: March 28, 2019, 07:20:34 am »
'* that > 0 is important as it returns a -1 which ANDed with k returns a nonzero value through some bitwise magical goodness.
Code: QB64: [Select]
  1. k=1
  2. a$="123456789"
  3. if k and (INSTR (a$,"2") > 0) then
  4. '* your code here
  5.  

OR
Code: QB64: [Select]
  1. k=1
  2. a$="123456789"
  3.   if instr(a$,"2") then
  4.   '* your code here
  5.   end if
  6.  
both of these will work as expected
« Last Edit: March 28, 2019, 07:26:23 am by codeguy »

Offline Qwerkey

  • Forum Resident
  • Posts: 755
    • View Profile
Re: INSTR() and AND...
« Reply #3 on: March 29, 2019, 05:57:42 am »
Coo, that is mind-scrambling for us ordinary mortals.  The maxim, then, is always use an equation where a number is concerned; only use True/False for actual Booleans.

ie always use the format: IF LEN(k$) > 0 AND INSTR(x$,k$) > 0 THEN

In fact, where an AND or an OR is used, I always include brackets around the comparisons even though they're not required: IF (LEN(k$) > 0) AND (INSTR(x$,k$) > 0) THEN, just to precisely highlight what things are being evaluated.