17.6.1.2191 SEARCH STRING

( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag )

Search the string specified by c-addr1 u1 for the string specified by c-addr2 u2. If flag is true, a match was found at c-addr3 with u3 characters remaining. If flag is false there was no match and c-addr3 is c-addr1 and u3 is u1.

Testing:

T{ : s2 S" abc"   ; -> }T
T{ : s3 S" jklmn" ; -> }T
T{ : s4 S" z"     ; -> }T
T{ : s5 S" mnoq"  ; -> }T
T{ : s6 S" 12345" ; -> }T
T{ : s7 S" "      ; -> }T

T{ s1 s2 SEARCH -> s1 <TRUE>  }T
T{ s1 s3 SEARCH -> s1  9 /STRING <TRUE>  }T
T{ s1 s4 SEARCH -> s1 25 /STRING <TRUE>  }T
T{ s1 s5 SEARCH -> s1 <FALSE> }T
T{ s1 s6 SEARCH -> s1 <FALSE> }T
T{ s1 s7 SEARCH -> s1 <TRUE>  }T

ContributeContributions

JimPetersonavatar of JimPeterson [295] Possible Reference ImplementationSuggested reference implementation2023-04-09 18:50:46

This is the best I could come up with for this one:

: SEARCH {: c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag :}
  c-addr1
  u1 u2 - 1+ 0 MAX 0 ?DO           \ only search up to u1-u2 characters
    DUP u2 c-addr2 u2 COMPARE 0= IF
      u1 I - TRUE UNLOOP EXIT      \ u3 is u1 minus however far we scanned in
    THEN
    CHAR+
  LOOP
  DROP
  c-addr1 u1 FALSE
;

The spec saying "... with u<sup>3 characters remaining." sounds a bit vague to me, but I took it to mean that c-addr3 u3 CHARS + c-addr1 u1 CHARS + =, which is to say that c-addr<sup>3 u<sup>3 is the tail end of the c-addr<sup>1 u<sup>1 string, where c-addr<sup>3 u<sup>2 is the same string as c-addr<sup>2 u<sup>2 (when a match is found)

There is also no mention of whether or not the search proceeds forwards from c-addr<sup>1 or backwards from c-addr<sup>1+u<sup>1-u<sup>2, or what happens if c-addr<sup>2 u<sup>2 appears multiple times in c-addr<sup>1 u<sup>1. It should maybe say "... for the first occurrence of the string specified by c-addr<sup>2 u<sup>2."

bfox9900avatar of bfox9900

Here is a version for systems without locals. Not sure it would be faster with all the stack manipulation but it works.

: SEARCH ( caddr1 u1 caddr2 u2 -- caddr3 u3 flag) BEGIN DUP WHILE 2OVER 2OVER DROP OVER COMPARE WHILE 1 /STRING
REPEAT 2NIP TRUE EXIT THEN 2NIP FALSE ;

bfox9900avatar of bfox9900

I should read the specification more closely. This correction gives the correct output if search fails to find the string. Reduced some stack juggling with the dreaded PICK.

: SEARCH  ( caddr1 u1 caddr2 u2 -- caddr3 u3 flag)
   BEGIN 
     DUP
   WHILE 
     2OVER  3 PICK  OVER  COMPARE 
   WHILE 
     1 /STRING  
   REPEAT
   2NIP  TRUE EXIT
   THEN
   2DROP FALSE ; 

```

bfox9900avatar of bfox9900

I was never good at following directions. Here is a version that actually provides the specified output for both cases; string found and string not found. Mea culpa

: SEARCH  ( caddr1 u1 caddr2 u2 -- caddr3 u3 flag)
   2OVER                \ retain a copy of 1st string 
   BEGIN 
     DUP
   WHILE 
     2OVER 4TH OVER COMPARE 
   WHILE 
     1 /STRING  
   REPEAT
   2NIP 2NIP TRUE EXIT      \ string found 
   THEN
   2DROP 2DROP FALSE ;   \ string not found 
Reply New Version