1/2 assed srfi-13 added by sethalves on Mon Feb 17 15:31:25 2014
;; -*- scheme -*- ;; srfi-13, String LIbraries ;; http://srfi.schemers.org/srfi-13/srfi-13.html ;; http://wiki.call-cc.org/man/4/Unit%20srfi-13 (define-library (snow srfi-13-strings) (export string-tokenize string-pad string-map string-trim string-trim-right string-trim-both string-take string-take-right string-join string-prefix? string-prefix-ci? string-suffix? string-suffix-ci? string-contains string-contains-ci substring/shared string-concatenate string-concatenate/shared string-append/shared string-concatenate-reverse string-concatenate-reverse/shared string-index string-index-right string-skip string-skip-right ;; XXX the rest... ) (import (scheme base)) (cond-expand (chibi (import (scheme char) (chibi char-set) (chibi char-set full) (srfi 8) (srfi 33) (chibi optional) )) (chicken (import (srfi 13))) (gauche (import (gauche) (srfi 13))) (sagittarius (import (srfi :13)))) (begin (cond-expand (chicken ;; (use srfi-13) ) ((or gauche sagittarius) #t) (else ;; XXX has anyone ported srfi-13 to chibi? ;; here is a partially and poorly implemented macroless ;; version of srfi-13 (define (string-tokenize s . token-chars+start+end) (let* ((args-len (length token-chars+start+end)) (token-chars (if (> args-len 0) (list-ref token-chars+start+end 0) char-set:graphic)) (start (if (> args-len 1) (list-ref token-chars+start+end 1) 0)) (end (if (> args-len 2) (list-ref token-chars+start+end 2) (string-length s)))) (reverse (let loop ((tokens '()) (current-token "") (s s)) (cond ((= (string-length s) 0) (if (> (string-length current-token) 0) (cons current-token tokens) tokens)) (else (let ((current-char (string-ref s 0)) (s (substring s 1 (string-length s)))) (cond ((token-chars current-char) (loop (tokens (string-append current-token current-char) s))) (else (loop (cons current-token tokens) "" s)))))))))) (define (string-pad str n . char+start+end) (let ((pad-char (if (null? char+start+end) #\space (car char+start+end)))) (let ((orig-length (string-length str))) (if (>= orig-length n) str (string-append (make-string (- n orig-length) pad-char) str))))) ;; (define (string-map proc s . maybe-start+end) ;; (list->string (map proc (string->list s)))) (define (string-trim-decider s i criterion) (or (and (procedure? criterion) (criterion (string-ref s i))) (and (char? criterion) (eqv? criterion (string-ref s i))) (and (char-set? criterion) (char-set-contains? criterion (string-ref s i))))) (define (string-trim-arguments s criterion+start+end) (let* ((oa-len (length criterion+start+end)) (criterion (if (> oa-len 0) (car criterion+start+end) char-set:whitespace)) (start (if (> oa-len 1) (cadr criterion+start+end) 0)) (end (if (> oa-len 2) (list-ref criterion+start+end 2) (string-length s)))) (values criterion start end))) (define (string-trim s . criterion+start+end) (receive (criterion start end) (string-trim-arguments s criterion+start+end) (let loop ((i start)) (cond ((= i end) "") ((string-trim-decider s i criterion) (loop (+ i 1))) (else (substring s i end)))))) (define (string-trim-right s . criterion+start+end) (receive (criterion start end) (string-trim-arguments s criterion+start+end) (let loop ((i end)) (cond ((= i start) "") ((string-trim-decider s (- i 1) criterion) (loop (- i 1))) (else (substring s start i)))))) (define (string-trim-both s . criterion+start+end) (receive (criterion start end) (string-trim-arguments s criterion+start+end) (let sloop ((si start)) (cond ((= si end) "") ((string-trim-decider s si criterion) (sloop (+ si 1))) (else (let eloop ((ei end)) (cond ((string-trim-decider s (- ei 1) criterion) (eloop (- ei 1))) (else (substring s si ei))))))))) (define (string-take s n) (substring s 0 n)) (define (string-take-right s n) (substring s (- (string-length s) n) (string-length s))) (define (string-join items delim) (if (null? items) "" (let loop ((result '()) (items items)) (if (null? items) (apply string-append (reverse (cdr result))) (loop (cons delim (cons (car items) result)) (cdr items)))))) (define (string-prefix-worker? s1 s2 tester opt-args) (let* ((olen (length opt-args)) (start1 (if (> olen 0) (list-ref opt-args 0) 0)) (end1 (if (> olen 1) (list-ref opt-args 1) (string-length s1))) (start2 (if (> olen 2) (list-ref opt-args 2) 0)) (end2 (if (> olen 3) (list-ref opt-args 3) (string-length s2)))) (let loop ((i1 start1) (i2 start2)) (cond ((= i1 end1) #t) ((= i2 end2) #f) ((not (tester (string-ref s1 i1) (string-ref s2 i2))) #f) (else (loop (+ i1 1) (+ i2 1))))))) (define (string-prefix? s1 s2 . opt-args) (string-prefix-worker? s1 s2 char=? opt-args)) (define (string-prefix-ci? s1 s2 . opt-args) (string-prefix-worker? s1 s2 char-ci=? opt-args)) (define (string-suffix-worker? s1 s2 tester opt-args) (let* ((olen (length opt-args)) (start1 (if (> olen 0) (list-ref opt-args 0) 0)) (end1 (if (> olen 1) (list-ref opt-args 1) (string-length s1))) (start2 (if (> olen 2) (list-ref opt-args 2) 0)) (end2 (if (> olen 3) (list-ref opt-args 3) (string-length s2)))) (let loop ((i1 (- end1 1)) (i2 (- end2 1))) (cond ((< i1 start1) #t) ((< i2 start2) #f) ((not (tester (string-ref s1 i1) (string-ref s2 i2))) #f) (else (loop (- i1 1) (- i2 1))))))) (define (string-suffix? s1 s2 . opt-args) (string-suffix-worker? s1 s2 char=? opt-args)) (define (string-suffix-ci? s1 s2 . opt-args) (string-suffix-worker? s1 s2 char-ci=? opt-args)) (define (string-contains-worker s1 s2 prefix? opt-args) (let* ((olen (length opt-args)) (start1 (if (> olen 0) (list-ref opt-args 0) 0)) (end1 (if (> olen 1) (list-ref opt-args 1) (string-length s1))) (start2 (if (> olen 2) (list-ref opt-args 2) 0)) (end2 (if (> olen 3) (list-ref opt-args 3) (string-length s2)))) (let loop ((i1 start1)) (cond ((= i1 end1) #f) ((prefix? s2 s1 start2 end2 i1 end1) i1) (else (loop (+ i1 1))))))) (define (string-contains s1 s2 . opt-args) (string-contains-worker s1 s2 string-prefix? opt-args)) (define (string-contains-ci s1 s2 . opt-args) (string-contains-worker s1 s2 string-prefix-ci? opt-args)) (define substring/shared substring) (define (string-concatenate args) (apply string-append args)) (define string-concatenate/shared string-concatenate) (define string-append/shared string-append) (define (string-concatenate-reverse string-list . oa) (let* ((oa-len (length oa)) (final-string-0 (if (> oa-len 0) (car oa) #f)) (end (if (> oa-len 1) (cadr oa) #f)) (final-string-1 (cond ((not final-string-0) #f) ((not end) final-string-0) (else (substring/shared final-string-0 0 end)))) (string-list (cond (final-string-1 (cons final-string-1 string-list)) (else string-list)))) (string-concatenate (reverse string-list)))) (define string-concatenate-reverse/shared string-concatenate-reverse) (define (string-index/skip-tester char/char-set/pred) (cond ((procedure? char/char-set/pred) char/char-set/pred) ((char-set? char/char-set/pred) (lambda (c) (char-set-contains? char/char-set/pred c))) (else (lambda (c) (eqv? c char/char-set/pred))))) (define (string-index/skip-start-end s start+end) (let* ((args-len (length start+end)) (start (if (> args-len 0) (list-ref start+end 0) 0)) (end (if (> args-len 1) (list-ref start+end 1) (string-length s)))) (values start end))) (define (string-index s char/char-set/pred . start+end) (let-values (((start end) (string-index/skip-start-end s start+end))) (let ((tester (string-index/skip-tester char/char-set/pred))) (let loop ((i start)) (cond ((>= i end) #f) ((tester (string-ref s i)) i) (else (loop (+ i 1)))))))) (define (string-index-right s char/char-set/pred . start+end) (let-values (((start end) (string-index/skip-start-end s start+end))) (let ((tester (string-index/skip-tester char/char-set/pred))) (let loop ((i (- end 1))) (cond ((< i start) #f) ((tester (string-ref s i)) i) (else (loop (- i 1)))))))) (define (string-skip s char/char-set/pred . start+end) (let-values (((start end) (string-index/skip-start-end s start+end))) (let* ((tester (string-index/skip-tester char/char-set/pred)) (stester (lambda (c) (not (tester c))))) (let loop ((i start)) (cond ((>= i end) #f) ((stester (string-ref s i)) i) (else (loop (+ i 1)))))))) (define (string-skip-right s char/char-set/pred . start+end) (let-values (((start end) (string-index/skip-start-end s start+end))) (let* ((tester (string-index/skip-tester char/char-set/pred)) (stester (lambda (c) (not (tester c))))) (let loop ((i (- end 1))) (cond ((< i start) #f) ((stester (string-ref s i)) i) (else (loop (- i 1)))))))) ))))