diff --git a/doc/reference/misc.md b/doc/reference/misc.md index c339a82c98..b8a7f5b5a2 100644 --- a/doc/reference/misc.md +++ b/doc/reference/misc.md @@ -5589,6 +5589,63 @@ characters (`[a-zA-Z0-9_]`). Throws an error if `len` is not a fixnum. ``` ::: +### str +``` scheme +(str . xs) -> string + + xs := values to be converted and concatenated into a string +``` +`str` converts all of its arguments into a single string. +When called without an argument an empty string is returned. + +::: tip Examples: +``` scheme +> (str) +"" + +> (str 2.0) +"2.0" + +> (str "hello" ", world") +"hello, world" + +> (import :std/format :std/misc/repr) +> (defstruct point (x y)) +> (def p (make-point 10 20)) +> (defmethod {:pr point} + (lambda (self port options) + (fprintf port "(point ~a ~a)" + (point-x self) (point-y self)))) + +> (str p 'abc [1 2] 3.4E+2) +"(point 10 20)abc[1 2]340.0" +``` +::: + +### str-format +``` scheme +(str-format v) -> string + + v := any value +``` +`str-format` takes any value and returns a formatting string, which can be +used by the `:std/format` family of procedures. Considers the `:pr` +[method](https://cons.io/reference/misc.html#representable) from `:std/misc/repr`. + +::: tip Examples: +``` scheme +> (import :std/format) +> (str-format "hello") +"~a" ; default format + +> (str-format 1.2E+2) +"~f" ; inexact number + +> (str-format (vector 1 2 3)) +"~r" ; object which implements the :pr method of :std/misc/repr +``` +::: + ### line ending variables ``` scheme (define +cr+ "\r") diff --git a/src/std/misc/string-test.ss b/src/std/misc/string-test.ss index 8520de0348..7b4fec0cbb 100644 --- a/src/std/misc/string-test.ss +++ b/src/std/misc/string-test.ss @@ -3,12 +3,17 @@ (import :std/misc/string :std/srfi/13 :std/test :gerbil/gambit/exceptions - :std/pregexp) + :std/pregexp :std/misc/repr :std/sugar :std/format) (def (error-with-message? message) (lambda (e) (and (error-exception? e) (equal? (error-exception-message e) message)))) +(defstruct point (x y)) +(defmethod {:pr point} + (lambda (self port options) + (fprintf port "(point ~a ~a)" (point-x self) (point-y self)))) + (def string-test (test-suite "test :std/misc/string" (test-case "string-split-suffix" @@ -65,4 +70,18 @@ (check-eq? (and (pregexp-match "^\\w+$" (random-string 100)) #t) #t) (check-equal? (random-string 0) "") (check-equal? (random-string -1) "") - (check-equal? (string-length (random-string 5)) 5)))) + (check-equal? (string-length (random-string 5)) 5)) + (test-case "test str" + (check (str) => "") + (check (str "hi") => "hi") + (check (str "hello" ", world.") => "hello, world.") + (check (str 0.1 "!") => "0.1!") + (check (str 2.0) => "2.0") + (check (str 1.2E+2) => "120.0") + (check (str 'abc) => "abc") + (check (str '(1 2)) => "[1 2]") + (check (str (hash (a 10))) => "(hash (a 10))") + (check (str #(1 2)) => "(vector 1 2)") + (check (str (values 1 2)) => "(values 1 2)") + (check (str (make-point 1 2)) => "(point 1 2)")) + )) diff --git a/src/std/misc/string.ss b/src/std/misc/string.ss index 1804b23501..869085b8c0 100644 --- a/src/std/misc/string.ss +++ b/src/std/misc/string.ss @@ -11,12 +11,15 @@ string-subst string-whitespace? random-string + str str-format +cr+ +lf+ +crlf+) (import (only-in :gerbil/gambit/ports write-substring write-string) (only-in :gerbil/gambit/random random-integer) - :std/srfi/13) + :std/srfi/13 + :std/format + ) ;; If the string starts with given prefix, return the end of the string after the prefix. ;; Otherwise, return the entire string. NB: Only remove the prefix once. @@ -215,3 +218,37 @@ (string-set! str i (random-word-char))) str) "")) + +;; str converts all of its arguments into a single string. +;; When called without an argument an empty string is returned. +;; +;; Examples: +;; (str 2.0) => "2.0" +;; (str "hello" ", world") => "hello, world" +(def* str + ((v) (if (string? v) v + (format (str-format v) v))) + (xs (call-with-output-string + (lambda (port) + (let loop ((rest xs)) + (match rest + ([v . rest] + (if (string? v) + (write-string v port) + (fprintf port (str-format v) v)) + (loop rest)) + (else (void)))))))) + +;; str-format takes any value and returns a formatting string, which can be +;; used by the :std/format family of procedures. Considers the :pr method +;; from :std/misc/repr. +;; +;; Examples: +;; (str-format 5.0) => "~f" +;; (str-format [1 2]) => "~r" +(def (str-format v) + (def (obj-pr? v) (method-ref v ':pr)) + (cond + ((? (and number? inexact?) v) "~f") + ((? (or list? hash-table? vector? ##values? obj-pr?) v) "~r") + (else "~a")))