Put double quotes for each string in a list of strings

Hi, y’ all!

I want to wrap each string from the list of strings in double quotes - so given a string:

my_string = "bilbao,   newcastle-upon-tyne, gothenburg,   munich    "

I expect a nicely formatted one:

my_string = "bilbao", "newcastle-upon-tyne", "gothenburg", "munich"

For now I only came up with some lame solution (due to fever?!..)

iex> my_string = "bilbao,   newcastle-upon-tyne, gothenburg,   munich    "
iex> IO.puts
     my_string
     |> String.split(",")
     |> Enum.map(&String.trim/1)
     |> Enum.map(&String.replace_prefix(&1, "", ~s(")))
     |> Enum.map(&String.replace_suffix(&1, "", ~s(")))
     |> Enum.join(", ")
"bilbao", "newcastle-upon-tyne", "gothenburg", "munich"

Requirements:

  • performance is not really important here,
  • output strings are same order as input strings,
  • strings are utf8,
  • prefer to avoid regex.

Thanks!

I’d just use string interpolation.

String.split(my_string, ",")
|> Enum.map(fn s ->
  s = String.trim(s)
  "\"#{s}\""
end)
|> Enum.join(", ")

Or string concatenation if you prefer.

String.split(my_string, ",")
|> Enum.map(fn s ->
  "\"" <> String.trim(s) <> "\""
end)
|> Enum.join(", ")

Your solution is calling map many times, each doing a single step. A single call to map can do all the steps necessary, regardless of string interpolation, concatenation, or replace.

2 Likes

Hi,

I was wondering if Kernel.inspect/1 would feet? (mostly in case a " needs to be escaped according to Elixir syntax)

"bilbao,   newcastle-upon-tyne, gothenburg,   munich    "
|> String.split(",")
|> Stream.map(&String.trim/1)
|> Stream.map(&inspect/1)
|> Enum.join(", ")
|> IO.puts()

Also, it is possible to regroup the Enum.map + Enum.join operations in the previous answer with Enum.map_join/3 :wink:

2 Likes

That’s a bummer, because this is a perfect situation to use the “split on Regex” feature of String.split:

my_string = "bilbao,   newcastle-upon-tyne, gothenburg,   munich    "

my_string
|> String.trim()
|> String.split(~r/,\s+/, trim: true)
|> Enum.map(&"#{&1}")
|> Enum.join(", ")

Some extension-points / places to customize the code:

  • the trim: true option to String.split prevents an empty "" at the end of the result if there’s a trailing , on the input. Your example didn’t specify what the behavior should be.

  • if the input values might contain ", you’ll want to make the Enum.map step smarter about escaping

  • commas in the input that aren’t followed by at least one space will be passed through unchanged. Whether that’s a bug or a feature depends on your expectations for the input.

NIT: Enum.map_join

1 Like

My requirements are very basic for now… However the regex is not preferred as if when the solution will later require that the string does not have a trailing comma, has a underscore in between words, may contain minimum two dots etc, then the regex itself becomes too much burden to think of (you can tell I’m a big fan of regex ;-])

BTW your solution does not return each word in double quotes. Corrected:

my_string
|> String.trim()
|> String.split(~r/,\s+/, trim: true)
|> Enum.map_join(", ", &inspect/1)