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