string interpolation

54 views
Skip to first unread message

Islon

unread,
Oct 27, 2008, 11:38:24 PM10/27/08
to clo...@googlegroups.com
Is there any chance closure will get string interpolation?

Do things like (prn "Hi ${someone}, my name is ${myname}") is nice, not crucial of course, but nice.

Islon

mb

unread,
Oct 28, 2008, 6:46:20 AM10/28/08
to Clojure
Hi Islon,
There is format.

user=> (def someone "World")
#=(var user/someone)
user=> (format "Hello %s!" someone)
"Hello World!"

Not exactly, what you want, but close. The format string syntax
is described at java.util.Formatter in the Java docs.

Sincerely
Meikel

Mike Benfield

unread,
Oct 28, 2008, 7:28:17 AM10/28/08
to Clojure
I've always preferred a function like str to either of these options
anyway.

(str "Hi " someone ", my name is " myname)

Graham Fawcett

unread,
Oct 28, 2008, 7:27:34 PM10/28/08
to clo...@googlegroups.com

I'm personally not fond of string interpolation either.

But for fun, here's an (i ...) macro, that will give you ${}
interpolation in strings (if it works at all, I test it very
thorougly!).


(defn my-interleave [a b]
"Like interleave, but uses all elements from both lists."
(loop [acc [] a a b b]
(if (and (nil? a) (nil? b))
acc
(let [acc2 (if (nil? a)
acc
(conj acc (first a)))
acc3 (if (nil? b)
acc2
(conj acc2 (first b)))]
(recur acc3 (rest a) (rest b))))))

(defn read-from-string [s]
(read (java.io.PushbackReader. (java.io.StringReader. s))))

(defn tokenize [s] ;; not pretty but it works.
(let [positions (let [mm (re-matcher #"\\$\\{.*?\\}" s)]
(loop [acc []]
(if (.find mm)
(recur (conj acc [(.start mm) (.end mm)]))
acc)))
intermed (conj (apply vector 0 (apply concat positions))
(.length s))
textposns (partition 2 intermed)]
(my-interleave (map (fn [[a b]] [:text (.substring s a b)]) textposns)
(map (fn [[a b]] [:pat (.substring s (+ a 2) (- b 1))])
positions))))

(defmacro i [s]
(apply list 'str
(map (fn [[type value]]
(if (= type :text)
value
(read-from-string value)))
(tokenize s))))

;; test

(let [greeting "Hello" name "Fred" age 33]
(prn (i "${greeting}, my name is ${name} and my age is ${age}.")))


-- Graham

Graham Fawcett

unread,
Oct 28, 2008, 7:29:41 PM10/28/08
to clo...@googlegroups.com
On Tue, Oct 28, 2008 at 7:27 PM, Graham Fawcett
<graham....@gmail.com> wrote:
> But for fun, here's an (i ...) macro, that will give you ${}
> interpolation in strings (if it works at all, I test it very
> thorougly!).

Haha, nor did I spell- or grammar-check very thoroughly!

I meant: I didn't test the code very thoroughly, so I hope it works at all.

Graham

islon

unread,
Oct 29, 2008, 10:17:08 AM10/29/08
to Clojure
Thanks for the macro. =)
The str function is really a good replacement for interpolation.

On Oct 28, 8:29 pm, "Graham Fawcett" <graham.fawc...@gmail.com> wrote:
> On Tue, Oct 28, 2008 at 7:27 PM, Graham Fawcett
>

Kyle R. Burton

unread,
Oct 29, 2008, 1:27:53 PM10/29/08
to clo...@googlegroups.com
> Thanks for the macro. =)
> The str function is really a good replacement for interpolation.

Yes, thank you for the macro. I anticipate using this approach (I'm
accustomed to it from Ruby, Perl and JScheme), but wanted to support a
way of stopping the parser (by backslashing the opening brace:
"$\\{x}" ). I think adding the zero-width assertion in the re-matcher
and the replaceAll to knock the backslash out gets me there:

(defn tokenize [s]
(let [positions (let [mm (re-matcher #"\\$(?!\\\\)\\{.*?\\}" s)]


(loop [acc []]
(if (.find mm)
(recur (conj acc [(.start mm) (.end mm)]))
acc)))
intermed (conj (apply vector 0 (apply concat positions))
(.length s))
textposns (partition 2 intermed)]

(my-interleave (map (fn [[a b]] [:text (. (.substring s a b)
(replaceAll "\\$\\\\\\{" "\\${"))])


textposns)
(map (fn [[a b]] [:pat (.substring s (+ a 2) (- b 1))])
positions))))

Regards,

Kyle Burton

Graham Fawcett

unread,
Oct 29, 2008, 1:54:17 PM10/29/08
to clo...@googlegroups.com
On Wed, Oct 29, 2008 at 1:27 PM, Kyle R. Burton <kyle....@gmail.com> wrote:
>
>> Thanks for the macro. =)
>> The str function is really a good replacement for interpolation.
>
> Yes, thank you for the macro. I anticipate using this approach (I'm
> accustomed to it from Ruby, Perl and JScheme), but wanted to support a
> way of stopping the parser (by backslashing the opening brace:
> "$\\{x}" ). I think adding the zero-width assertion in the re-matcher
> and the replaceAll to knock the backslash out gets me there:

You're very welcome! The backslash-fix makes good sense.

Graham

Reply all
Reply to author
Forward
0 new messages