Sure, there's existing code. Somebody Else's Code. It works fine, maybe not as fast as you'd like, or the interface isn't quite right. That's how it often is with me and SRFI-13. Olin Shivers is a skilled Schemer, back when that wasn't cool (OK, it's still not cool), but some of his APIs enshrined in early SRFIs drive me a little nuts, and the implementation is slow because it's so generalized.
So after a few false starts and failed tests, I now have these pretty things: (updated 2020-11-10, enforced hstart, hend boundaries)
;; Returns index of `needle` in `haystack`, or #f if not found.
;; `cmp`: Comparator. Default `char=?`, `char-ci=?` is the most useful alternate comparator.
;; `hstart`: Starting index, default 0.
;; `hend`: Ending index, default (- haystack-length needle-length)
(define string-find (case-lambda
[(haystack needle) (string-find haystack needle char=? 0 #f)]
[(haystack needle cmp) (string-find haystack needle cmp 0 #f)]
[(haystack needle cmp hstart) (string-find haystack needle cmp hstart #f) ]
[(haystack needle cmp hstart hend)
(let* [ (hlen (string-length haystack)) (nlen (string-length needle)) ]
(set! hstart (max 0 (min hstart (sub1 hlen))))
(unless hend (set! hend (fx- hlen nlen)))
(set! hend (max 0 (min hend hlen)) )
(if (or (fxzero? hlen) (fxzero? nlen))
#f
(let loop [ (hi hstart) (ni 0) ]
;; assume (< ni nlen)
;(errprintln "hi=" hi ", ni=" ni ", hsub=" (substr haystack hi hlen) ", bsub=" (substr needle ni nlen))
(cond
[(cmp (string-ref haystack (fx+ hi ni)) (string-ref needle ni)) (set! ni (fx+ ni 1))
;; end of needle?
(if (fx>=? ni nlen) hi (loop hi ni) )
]
[else (set! hi (fx+ hi 1))
;; end of haystack?
(if (fx>? hi hend) #f (loop hi 0) )
]
))))
]
))
;; Test whether 'haystack' starts with 'needle'.
(define (string-has-prefix? haystack needle)
(let [ (i (string-find haystack needle char=? 0 0)) ]
(and i (fxzero? i))
))
;; Test whether 'haystack' ends with 'needle'.
(define (string-has-suffix? haystack needle)
(let* [ (hlen (string-length haystack)) (nlen (string-length needle))
(i (string-find haystack needle char=? (fx- hlen nlen)))
]
(and i (fx=? i (fx- hlen nlen)))
))
Written for Chez Scheme, caveat implementor. BSD license, do what thou wilt. If you find a bug, send me a failing test case.
I don't normally bother with fx (fixnum) operations, but in tight loops it makes a difference over generic numeric tower +, etc.