Replace specific occurrences in a string

I have a string like this:

 "api/v1/contact/request/type"

I wan to replace the last two occurrence of / to make the string the string lie this:

 "api/v1/contact-request-type"

I look up atRegex methods but didn’t find replacing specific characters

Thanks!

If this is really about the last "/" and the number of segments varies, then the following would probably be the easiest:

iex(1)> [a, b|c] = "api/v1/contact/request" |> String.split("/") |> Enum.reverse 
["request", "contact", "v1", "api"]
iex(2)> ((c |> Enum.reverse) ++ [b <> "-" <> a]) |> Enum.join("/")
"api/v1/contact-request"

This will raise though, when there is no slash in the input.

this should work also without slashes, but is a little monster. :slight_smile:

Regex.replace(~r/(.+)\/((?:.(?!\/))+)$/, "api/v1/contact/request", "\\1-\\2") 
4 Likes

I was having the same idea

iex> Regex.replace ~r/\/(\w*)$/, "api/v1/contact/request", "-\\1"
"api/v1/contact-request"
2 Likes

Thanks for your answer. I just edited the question can you please edit your answer.

Thanks

The edited version of your question says “last occurence” but replaces more than one occurence. So I have trouble to actually figure out your exact requirements…

just updated the question. Last two occurences

iex> Regex.replace ~r/\/(\w*)\/(\w*)$/, "api/v1/contact/request", "-\\1-\\2"
"api/v1-contact-request"

BTW after some replies, it would be better to ask a more precise question without changing the topic :slight_smile:

You might find this more precise too…

iex> Regex.replace ~r/\/([^\/]*)\/([^\/]*)$/, "api/v1/contact/request", "-\\1-\\2"
"api/v1-contact-request"
1 Like

It should be easy to adopt my solution then.

Yes I will next time. Thanks.

sure thanks.

Based on my first solution I built something more generic for any given n:

defmodule Replacer do
  def replace_n(str, n, pat, subst) do
    {back, front} =
      str
      |> String.split(pat)
      |> Enum.reverse()
      |> Enum.split(n)

    back = Enum.join(back, subst)

    [back | front]
    |> Enum.reverse()
    |> Enum.join(pat)
  end
end

which also does not raise on mismatch of pat count:

iex(1)> Replacer.replace_n("api/v1/contact/request/type", 3, "/", "-")
"api/v1/type-request-contact"
iex(2)> Replacer.replace_n("api/v1/contact/request/type", 2, "/", "-")
"api/v1/contact/type-request"
iex(3)> Replacer.replace_n("api/v1/contact/request/type", 1, "/", "-")
"api/v1/contact/request/type"
iex(4)> Replacer.replace_n("api/v1/contact/request/type", 10, "/", "-")
"type-request-contact-v1-api"

edit

And I just realized a bug :wink:

To fix that bug change |> Enum.split(n) to |> Enum.split(n + 1).

1 Like

If You like functions… You can create an anonymous one, which replace the last, and apply it multiple time :slight_smile:

iex> repl = fn s -> Regex.replace ~r/\/([^\/]*)$/, s, "-\\1" end
iex> "api/v1/contact/request-ok?111=5" |> repl.() |> repl.()    
"api/v1-contact-request-ok?111=5"
1 Like