[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Proposed amendments to SRFI-13

This page is part of the web mail archives of SRFI 13 from before July 7th, 2015. The new archives for SRFI 13 contain all messages, not just those from before July 7th, 2015.



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))