[racket] String manipulation without regex opinion

From: Ryan Culpepper (ryan at cs.utah.edu)
Date: Tue Nov 6 15:23:48 EST 2012

On 11/06/2012 02:59 PM, Grant Rettke wrote:
> Hi,
>
> Usually there are homework problems and stuff for tweaking strings but I
> was just playing around for the fun of it. I wondered what is the "best
> way" to do a couple of simple tasks but without regex. Here are two of
> them. They are not optimized I just wrote them in a way that seemed the
> simplest. What is a better way or different way?
>
> #lang racket
>
> (require rackunit)
>
> ;; string -> string
> ;; Removes vowels from the input
> (define remove-vowels
>    (lambda (word)
>      (let ((test (lambda (c) (not (member c (list #\a #\e #\i #\o #\u)))))
>            (ls (string->list word)))
>        (list->string (filter test ls)))))

Here's one alternative that should allocate half as many intermediate 
pairs (by switching from string->list and filter to in-string and #:unless):

(define (remove-vowels s)
   (list->string
    (for/list ([c (in-string s)]
               #:unless (memv c '(#\a #\e #\i #\o #\u)))
      c)))

If I were really worried about performance, I would allocate a new 
string the size of the old string and copy characters from old to new, 
skipping vowels, and take the appropriate substring at the end. I might 
also delay the allocation of the copy until I found the first vowel; if 
there are no values, then the function can just return the string itself 
(unless the function needs to return a fresh string because of mutation 
elsewhere in the program).

> (check-equal? (remove-vowels "") "")
> (check-equal? (remove-vowels "f") "f")
> (check-equal? (remove-vowels "a e i o u") "    ")
>
> ;; string -> string
> ;; Replaces spaces in the input with dashes
> (define replace-spaces
>   (lambda (word)
>     (let ((test (lambda (c) (if (equal? c #\space) #\- c)))
>           (ls (string->list word)))
>       (list->string (map test ls)))))
>
> (check-equal? (replace-spaces "") "")
> (check-equal? (replace-spaces " ") "-")
> (check-equal? (replace-spaces "a b c") "a-b-c")

Similar, except here you wouldn't have to worry about resizing the copy 
at the end.

Ryan


Posted on the users mailing list.