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.