; -*- Scheme -*-
;
; $Id: string34.scm,v 1.1 1998/03/16 07:59:50 foner Exp $

(require 'char-set:member?)

;+doc
; procedure: string:split-by-chars-no-dups
; arguments: string char-set 
; signature: string x char-set -> list[string]
;
; Returns a list of words delimited by the characters in CHAR-SET in
; STRING.  If STRING is empty or contains only the characters in
; CHAR-SET, then the empty list is returned
;
; This is based on the split function in Python, which I believe is
; based on the Perl/Awk one.
;
; > (string:split-by-chars-no-dups ":abc:d:e:f:" (string->char-set ":"))
; ("abc" "d" "e" "f")
;
; > (string:split-by-chars-no-dups "::abc:d:::e:f:" (string->char-set ":"))
; ("abc" "d" "e" "f")
;
; > (string:split-by-chars-no-dups "" (string->char-set ":"))
; ()
;
; > (string:split-by-chars-no-dups "a" (string->char-set ":"))
; ("a")
;-doc

(define string:split-by-chars-no-dups
  (lambda (s cs)
    (let ((result '()) (sl (string-length s)))
      (if (zero? sl)
	  result
	  (let loop ((s s) (sp sl) (r result))
	    (let ((nwp (string::skip-chars s cs sp)))
	      (if (zero? nwp)
		  r
		  (let* ((nsp (string::skip-non-chars s cs nwp))
			 (nr (cons (substring s nsp nwp) r)))
		    (if (zero? nsp) nr (loop s (- nsp 1) nr))))))))))

; This could be written in terms of STRING:FIND-CHARS, but don't
; bother unless you can manage to make it tail recursive like the
; above.

;-------------

(define string::skip-chars
  (lambda (s cs i)
    (cond
     ((zero? i) i)
     ((char-set:member? cs (string-ref s (- i 1)))
      (string::skip-chars s cs (- i 1)))
     (else i))))
    
(define string::skip-non-chars
  (lambda (s cs i)
    (cond
     ((zero? i) i)
     ((char-set:member? cs (string-ref s (- i 1))) i)
     (else (string::skip-non-chars s cs (- i 1))))))

; eof
