Proposed amendments to SRFI-13
Donald Welsh 23 Oct 1999 12:15 UTC
Hello everyone. A few comments and suggestions on SRFI-13.
string-take
string-drop
string-take-right
string-drop-right
substring-move-left
substring-move-right
These (if needed) can all be defined as special cases of a more general
function, string-replace.
string-replace s1 start end s2 -> string
replace the substring of s1 from start to end with s2
A variant, string-replace! could also be defined, which is allowed to reuse
the original storage of s1.
With a regexp package, regexp matching could used to find start and end
points, then string-replace could perform the replacement.
My sample code defines two equivalent versions of string-replace.
String-replace-simple does string replacement using substrings and append;
string-replace allocates a new string and copies characters into it.
------------
reverse-string-concatenate string-list [end] -> string
reverse-string-concatenate/shared string-list [end] -> string
Why are these included? Without the optional parameter, the stated
equivalents are clearer. With END these functions are odd -- why are they
needed?
------------
string-filter s char/char-set/pred [start end] -> string
string-delete s char/char-set/pred [start end] -> string
The char/char-set/pred isn't intuitive. If char-sets are needed, perhaps
there should be a set package SRFI (is there one already?), or the
functionality could be provided by a regexp package. Suggest dropping
string-delete and using an alternative version of string-filter which uses
a string -> string function f instead of char/char-set/pred. (String
deletion can be done by f returning "".) The function f should go first,
as with map and string-map.
string-filter f s [start end] -> string
construct a string by applying f to each character of s
function f should take a string of length one as input, and output a
string (of any length)
------------
Example code (written in MzScheme) is below. Enjoy.
;;; dw-string.scm -- a few string manipulation functions
;;; these functions are for illustration, and lack error checking
; filter a string s using function f
(define (string-filter f s . endpoints)
(let ((start 0)
(end (string-length s)))
(if (not (null? endpoints))
(begin
(set! start (car endpoints))
(set! end (cadr endpoints))))
(string-append
(substring s 0 start)
(apply string-append
(map f
(map string
(string->list (substring s start end)))))
(substring s end (string-length s)))))
; map a character-transforming function over a string
; does not take substring endpoints
(define (string-map f s)
(list->string
(map f
(string->list s))))
; destructive version of string-map
; modifies the original string
; does not take substring endpoints
(define (string-map! f s)
(do ((i (- (string-length s) 1) (- i 1)))
((< i 0) 'ok)
(string-set! s i (f (string-ref s i)))))
; replace substring of s1 with s2
(define (string-replace-simple s1 start end s2)
(string-append (substring s1 0 start)
s2
(substring s1 end (string-length s1))))
; string-copy!, needed for efficient version of replacement
; substring endpoints should be optional
(define (string-copy! target tstart s start end)
(do ((i tstart (+ i 1))
(j start (+ j 1)))
((= j end) 'ok)
(string-set! target i (string-ref s j))))
; replacement, efficient version
; equivalent to string-replace-simple
(define (string-replace s1 start end s2)
(let ((result
(make-string
(+ (string-length s1)
(- start end) ; this should be nonpositive
(string-length s2)))))
; copy first part of s1 into result
(string-copy! result 0 s1 0 start)
; copy s2 into result
(string-copy! result start s2 0 (string-length s2))
; copy second part of s1 into result
(string-copy! result (+ start (string-length s2))
s1 end (string-length s1))
; return result
result))
;; the first two functions below demonstrate uses of string-filter
;; which could not be done by string-map
; test string-filter: remove the vowels from a string
(define (remove-vowels s)
(string-filter
(lambda (s1)
(if (member (string-ref s1 0)
(string->list "AEIOUaeiou"))
""
(substring s1 0 1)))
s))
; another example of string-filter
(define (local-echo s)
(string-filter
(lambda (s1)
(string-append s1 s1))
s))
;; example of using string-map
; rot13 of a character
(define (rot13 c)
(cond ((char-upper-case? c)
(integer->char
(if (char<? c #\N)
(+ (char->integer c) 13)
(- (char->integer c) 13))))
((char-lower-case? c)
(integer->char
(if (char<? c #\n)
(+ (char->integer c) 13)
(- (char->integer c) 13))))
(else c)))
; rot13 of a string
(define (string-rot13 s)
(string-map rot13 s))