(chapter-start ‘string-manipulation “utilities for manipulating strings”)

; return a new string with leading and trailing whitespace removed (def string-strip (txt)

(string-replace "(\\A\\s+|\\s+\\z)" "" txt))

;; flatten ‘things into a single list (ie unnest lists) ;; convert each item to a string ;; return a single string which is the concatenation of each ;; stringified item, with given ’txt inserted in between ;; each item (def joinstr (txt . things)

(let joinables (flatten things)
  (apply +
         (to-string:car joinables)
         (flatten (map (fn (x) (list txt x))
                       (cdr joinables))))))

;; stringify join all the things and join them with no separator, like (joinstr “” things) (def j things

(apply + "" (flatmap to-string things)))

;; string-interpolation syntax emits this form. Default implementation ;; is to delegate to ‘j , but containing forms may use macros that ;; override this in order to provide specific interpolation behaviour ;; (for example, formatting numbers or stripping HTML tags) (def string-pieces pieces

(j pieces))

; return the first ‘length chars of string ’str (def string-truncate (str length)

(string-replace "(.{~|length|}).*" "\\1" str))

;; returns a function with args ‘args whose body is ’str. ‘str should be a string, ;; ’args should correspond to interpolations within ‘str ;; ;; example: (string-eval-fn “hello ~u.firstname” ’u) ;; returns (fn (u) (string-pieces “hello ” u.firstname)) (defmemo string-eval-fn (str args)

(eval `(fn ,args
           ,(parse-in-string str))))

;; assigns ‘args respectively to ’arg-names and evals ‘str in that context. ;; Assumes ’str contains interpolations which reference ‘arg-names. ;; Useful for evaluating user-supplied strings ; dangerous for the same reason. ;; ;; example: (string/eval-with-args “~x + ~y is ~(+ x y)” ’(x y) 2 3) ;; returns “2 + 3 is 5” ;; (def string/eval-with-args (str arg-names . args)

(on-err
 (error (j "error evaluating "  (inspect str)
           "\nwith arg names "  (inspect arg-names)
           "\nand args "        (inspect args)))
 (apply (string-eval-fn str arg-names)
        args)))

;; if txt is not blank/empty, return concatenation of before, txt, after (def maybe-wrap-text (txt before after)

(if (nb txt)
    (j before txt after)
    txt))