(module str (lib "swindle.ss" "swindle") ;(trim before after string-drop-until string-take-until string-split) ;(import srfi13/string) "str.ss -- string manipulaion beyond the Scheme SRFI, which seems to include all the Useless Functions Many thanks to Oleg Kiselyov for string-split in particular, and mind-bending coolness in general." (require (only (lib "13.ss" "srfi") string-trim-both string-null? string-take string-drop string-contains string-join)) (provide (all-defined)) (define trim string-trim-both) (define (replace s from to) (bind i (string-contains s from) (if i (string-concat (string-take s i) to (replace (string-drop s (+ i (string-length from))) from to)) s))) (define (squash-newlines s) (replace (replace s "\r" " ") "\n" " ")) (define (remove-newlines s) (replace (replace s "\r" "") "\n" "")) (define (after s start) (let ((pos (string-contains s start))) (if pos (string-drop s (+ pos (string-length start))) ""))) (define (before s end) (let ((pos (string-contains s end))) (if pos (string-take s pos) ""))) (define (between s start end) (let ((pos (string-contains s start))) (if pos (let* ((start-pos (+ pos (string-length start))) (end-pos (string-contains s end start-pos))) (if end-pos (substring s start-pos end-pos) "")) ""))) (define (not-between s start end) (let ((pos (string-contains s start))) (if pos (let* ((start-pos pos) (end-pos (string-contains s end start-pos))) (if end-pos (string-append (string-take s start-pos) (string-drop s (+ end-pos (string-length end)))) "")) ""))) (define (last-word s . seps) (last (string-split s seps))) (define (chomp s . c) (let ((c (if (null? c) #\Newline (car c))) (last (sub1 (string-length s)))) (if (char=? (string-ref s last) c) (substring s 0 last) s))) (define (string-drop-until fn s) (let take ((i 0)) (if (fn (string-drop s i)) (string-drop s i) (take (add1 i))))) (define (string-take-until fn s) (let take ((i 0)) (if (fn (string-drop s i)) (string-take s i) (take (add1 i))))) (define (join ss &opt (sep " ")) "(list str)*str->str--for more options, use string-join" (string-join ss sep)) (define (format-list format-string l &key [sep "\n"] [default ""]) (if (null? l) default (join (map (lambda (s) (format format-string s)) l) sep))) (define (split s sep) "str*str->(list str)--for more options, use string-split" (bind i (string-contains s sep) (if i (cons (string-take s i) (split (string-drop s (+ i (string-length sep))) sep)) (list s)))) (define (split-save s seps) (let* ((sep (find-if (cur string-contains s) seps)) (i (string-contains s sep))) (if i (cons (string-take s i) (cons sep (split (string-drop s (+ i (string-length sep))) sep))) (list s)))) ; ; -- procedure+: string-split STRING ; -- procedure+: string-split STRING '() ; -- procedure+: string-split STRING '() MAXSPLIT ; ; Returns a list of whitespace delimited words in STRING. ; If STRING is empty or contains only whitespace, then the empty list ; is returned. Leading and trailing whitespaces are trimmed. ; If MAXSPLIT is specified and positive, the resulting list will ; contain at most MAXSPLIT elements, the last of which is the string ; remaining after (MAXSPLIT - 1) splits. If MAXSPLIT is specified and ; non-positive, the empty list is returned. "In time critical ; applications it behooves you not to split into more fields than you ; really need." ; ; -- procedure+: string-split STRING CHARSET ; -- procedure+: string-split STRING CHARSET MAXSPLIT ; ; Returns a list of words delimited by the characters in CHARSET in ; STRING. CHARSET is a list of characters that are treated as delimiters. ; Leading or trailing delimeters are NOT trimmed. That is, the resulting ; list will have as many initial empty string elements as there are ; leading delimiters in STRING. ; ; If MAXSPLIT is specified and positive, the resulting list will ; contain at most MAXSPLIT elements, the last of which is the string ; remaining after (MAXSPLIT - 1) splits. If MAXSPLIT is specified and ; non-positive, the empty list is returned. "In time critical ; applications it behooves you not to split into more fields than you ; really need." ; ; This is based on the split function in Python/Perl ; ; (string-split " abc d e f ") ==> ("abc" "d" "e" "f") ; (string-split " abc d e f " '() 1) ==> ("abc d e f ") ; (string-split " abc d e f " '() 0) ==> () ; (string-split ":abc:d:e::f:" '(#\:)) ==> ("" "abc" "d" "e" "" "f" "") ; (string-split ":" '(#\:)) ==> ("" "") ; (string-split "root:x:0:0:Lord" '(#\:) 2) ==> ("root" "x:0:0:Lord") ; (string-split "/usr/local/bin:/usr/bin:/usr/ucb/bin" '(#\:)) ; ==> ("/usr/local/bin" "/usr/bin" "/usr/ucb/bin") ; (string-split "/usr/local/bin" '(#\/)) ==> ("" "usr" "local" "bin") (define (string-split str . rest) (define inc 1+) ; maxsplit is a positive number (define (split-by-whitespace str maxsplit) (define (skip-ws i yet-to-split-count) (cond ((>= i (string-length str)) '()) ((char-whitespace? (string-ref str i)) (skip-ws (inc i) yet-to-split-count)) (else (scan-beg-word (inc i) i yet-to-split-count)))) (define (scan-beg-word i from yet-to-split-count) (cond ((zero? yet-to-split-count) (cons (substring str from (string-length str)) '())) (else (scan-word i from yet-to-split-count)))) (define (scan-word i from yet-to-split-count) (cond ((>= i (string-length str)) (cons (substring str from i) '())) ((char-whitespace? (string-ref str i)) (cons (substring str from i) (skip-ws (inc i) (- yet-to-split-count 1)))) (else (scan-word (inc i) from yet-to-split-count)))) (skip-ws 0 (- maxsplit 1))) ; maxsplit is a positive number ; str is not empty (define (split-by-charset str delimeters maxsplit) (define (scan-beg-word from yet-to-split-count) (cond ((>= from (string-length str)) '("")) ((zero? yet-to-split-count) (cons (substring str from (string-length str)) '())) (else (scan-word from from yet-to-split-count)))) (define (scan-word i from yet-to-split-count) (cond ((>= i (string-length str)) (cons (substring str from i) '())) ((memq (string-ref str i) delimeters) (cons (substring str from i) (scan-beg-word (inc i) (- yet-to-split-count 1)))) (else (scan-word (inc i) from yet-to-split-count)))) (scan-beg-word 0 (- maxsplit 1))) ; resolver of overloading... ; if omitted, maxsplit defaults to ; (inc (string-length str)) (if (string-null? str) '() (if (null? rest) (split-by-whitespace str (inc (string-length str))) (let ((charset (car rest)) (maxsplit (if (pair? (cdr rest)) (cadr rest) (inc (string-length str))))) (cond ((not (positive? maxsplit)) '()) ((null? charset) (split-by-whitespace str maxsplit)) (else (split-by-charset str charset maxsplit)))))) ))