string-escaper brlewis@xxxxxx 22 Nov 1999 19:28 UTC
> I've found string hacking to be a fundamental component of many different > kinds of hacking I've done -- web servers and scripting in particular. So > I'm very interested in developing a rich, carefully-thought-out library > that will assist this kind of programming. In my web server scripting I often have to escape strings into HTML or LaTeX. I understand some people have to escape strings to safely pass to a Unix shell. All of these are cases of escaping single characters into multiple characters for the output string. I think the string library would be more useful with some efficient mechanism for implementing such escapes. Here's a sample implementation to help fuel discussion: ;; examples of use (define html-escape (string-escaper '((#\< . "<") (#\> . ">") (#\& . "&")))) (define scheme-escape (string-escaper '((#\\ . "\\\\") (#\" . "\\\"")))) (define latex-escape (string-escaper '((#\\ . "\\\\") (#\~ . "\\~") (#\# . "\\#") (#\$ . "\\$") (#\% . "\\%") (#\^ . "\\^") (#\& . "\\&") (#\{ . "\\{") (#\} . "\\}") (#\_ . "\\_")))) ;; example implementation (define (string-escaper esc) (let ((spec (char-escape-spec esc))) (lambda (str) (string-escape str spec)))) (define (string-needs-escape? str esc) (let ((len (string-length str))) (let loop ((i 0)) (if (= i len) #f (let ((c (string-ref str i))) (if (and (char>=? c (car esc)) (char<=? c (cadr esc))) #t (loop (+ 1 i)))))))) (define (string-escape str esc) (if (string-needs-escape? str esc) (list->string (reverse (let ((len (string-length str))) (let loop ((i 0) (li '())) (if (= i len) li (loop (+ 1 i) (let ((c (string-ref str i))) (if (and (char>=? c (car esc)) (char<=? c (cadr esc))) (let ((li2 (vector-ref (caddr esc) (- (char->integer c) (char->integer (car esc)))))) (if li2 (append li2 li) (cons c li))) (cons c li))))))))) str)) (define (char-escape-spec speclist) (let ((minchar (caar speclist)) (maxchar (caar speclist))) (let loop ((li (cdr speclist))) (if (not (null? li)) (begin (let ((testchar (caar li))) (if (char<? testchar minchar) (set! minchar testchar)) (if (char>? testchar maxchar) (set! maxchar testchar))) (loop (cdr li))))) (list minchar maxchar (let ((specv (make-vector (+ 1 (- (char->integer maxchar) (char->integer minchar))) #f))) (map (lambda (specpair) (vector-set! specv (- (char->integer (car specpair)) (char->integer minchar)) (reverse (string->list (cdr specpair))))) speclist) specv))))