Clojure: string interpolation
We have a URL with some placeholder values that we want to replace.
"https://www.shop.com/$seller/items/$item-code/prices/$currency"
str
One way of doing this is to use str
function.
(defn shop-url [seller item-code currency]
(str "https://www.shop.com/" seller
"/items/" item-code
"/prices/" currency))
(shop-url "bob" "A567" "EUR")
=> "https://www.shop.com/bob/items/A567/prices/EUR"
There's nothing wrong with this solution. However, it does encapsulate/hide information that might be useful at the call site: order of arguments and what URL it is operating on.
format
Another approach would be to use the format
function, which gives us string interpolation.
(format "https://www.shop.com/%s/items/%s/prices/%s"
"bob"
"A567"
"EUR")
=> "https://www.shop.com/bob/items/A567/prices/EUR"
The downside of this is that the placeholders in the URL are not self-documenting.
replace-several
What about using a string replace function? Clojure core does have functions for replacing matches in strings, but it doesn't have a built-in function for replacing multiple different matches. Let's see how we could implement our own replace-several
function.
(defn replace-several [s & {:as replacements}]
(reduce (fn [s [match replacement]]
(clojure.string/replace s match replacement))
s replacements))
(replace-several "https://www.shop.com/$seller/items/$item-code/prices/$currency"
"$seller" "bob"
"$item-code" "A567"
"$currency" "EUR")
=> "https://www.shop.com/bob/items/A567/prices/EUR"
The above works and reads better than our previous solutions as the value substitutions are clear. If you find the destructuring in the reduce
a bit cumbersome you can use reduce-kv
which returns the accumulator, key and values for us.
(defn replace-several [s & {:as replacements}]
(reduce-kv clojure.string/replace s replacements))
Hopefully, these examples come in handy the next time you need some pseudo-string interpolation.