How to make String with Placeholders?

Hi Experts,

I am looking for built in function something like String builder with Placeholders.
Iet say in C like languages usuall you wold have function that looks like:

print(" Some string %placeholder1, string continues…%placeholder2 ", var1, var2)
#vars goes to placeholders

`Do we have something similar in Elixir ?

Use Case:
User provides: custom url with placeholders and separately details.
Then later url should be combined with data into proper url.

User: 223344
Lang: eng
Type: json | xml

Original URL

http: // somesite. com/?i=#{id}&lang=#{language}&type=api&api_v=1&api_type=#{data_type}"

Updated URL

https: // somesite. com/?i=#223344&lang=#eng&type=api&api_v=1&api_type=#json"

Do You mean string interpolation?

Because it does…

iex> id = 223344
223344
iex> lang = "eng"
"eng"
iex> type = "json"
"json"
iex> url = "http: // somesite. com/?i=#{id}&lang=#{lang}&type=api&api_v=1&api_type=#{type}"
"http: // somesite. com/?i=223344&lang=eng&type=api&api_v=1&api_type=json"

Now in your result #223344… It would be ##{id} if You really want #

Maybe not the simplest option but also works

iex(1)> template = "http://somesite.com/?i=#<%=id%>&lang=#<%=language%>&type=api&api_v=1&api_type=#<%=data_type%>"
"http://somesite.com/?i=#<%=id%>&lang=#<%=language%>&type=api&api_v=1&api_type=#<%=data_type%>"
iex(2)> EEx.eval_string(template, [id: 1, language: "pt-BR", data_type: "json"])
"http://somesite.com/?i=#1&lang=#pt-BR&type=api&api_v=1&api_type=#json"
5 Likes

Almost…it works in iex, but no in code… this is that I mean:

def prit_url(id, lang, url) do
   IO.puts url
do

How this function should look like, so user’s ID and LANG would go to URL ?

Hm… yeap, looks like a temporary solutionm but I wonder, maybe there is something nicer ? :smiley:

If You can have an url like this…

iex> url = "http://somesite.com/?i=%{id}&lang=%{language}&type=api&api_v=1&api_type=%{data_type}"

I just changed # for % to have a valid string…

Then You could

iex> url |> String.split("%")                                                                    
["http://somesite.com/?i=", "{id}&lang=",
 "{language}&type=api&api_v=1&api_type=", "{data_type}"]

And on each substring starting with {} You would…

id=223344
s = "{id}&lang=" 
s |> String.replace(~r/^{.}/, id)

But it is a little bit hackish…

Yep…
Well, I know that I can parse url…

The point is that this solution is not flexible…
This would work good on static urls, that do not change…

In cases where url can be any, probably it is better to use cpgo’s solution.
In my case I cant know in advance all possible urls, but I can tell user use the fallowing layout… and the test if user provides url according to layout and if it is matches then execute as a template…

Thank you guys for help ! :slight_smile:

You should generally be using the URI module to deal with URLs: https://hexdocs.pm/elixir/URI.html
That will handle the escaping, otherwise you will have plenty of surprises with strange data.

One way is with Michał Muskała’s Format library https://github.com/michalmuskala/format. I’m not sure if there’s any documentation, but you can do:

def print_url(id, language, url) do
  url
  |> Format.compile()
  |> Format.string(id: id, language: language)
  |> IO.puts()
end

where url is a string that contains {id} and {language}, which get replaced by the corresponding values specified in Format.string.

My personal syntactic preference would be

...
  |> Format.string([id: id, language: language])
...
2 Likes

Hi jakemorrison,

Thank you for a good point. :+1: You are absolutely right.

Hi jfeng,

Thank you for advice :+1 , but I probably had to mentioned that I would prefer not to add extra dependencies. Meanwhile, I can have a look, into their code and analyse it to get more ideas.

Format is rather experimental right now and has some issues especially around formatting floats. Maybe I should finally get into it an finish it, now that Jason is mostly done :wink:

3 Likes

Are you using Phoenix by any chance? If so take a look at:

https://hexdocs.pm/phoenix/routing.html#path-helpers

Might give you some ideas regardless…

I suggest you to use :io_lib.format(format, [arg1, ...]) |> to_string(). See the documentation of :io_lib.format.

It is one less dependency if you use this function because it is in the standard library.

2 Likes

It is a bit awkward, that there is no nicer way