0

I have following urls :

https://test1.com/path?query1=value1

and

https://test2.com/path

I am trying to add additional query param to all urls, so i am trying something like

url.replaceAll(/(.*)[?]?(.*)/g,"$1?newquery=newvalue&$2")

let url = "https://test1.com/path?query1=value1"
console.log(url.replaceAll(/^(.*)[?]?(.*)$/g,"$1?newquery=newvalue&$2"))
url = "https://test1.com/path"
console.log(url.replaceAll(/^(.*)[?]?(.*)$/g,"$1?newquery=newvalue&$2"))

But it doesnt work as expected , could someone shed some light

PDHide
  • 18,113
  • 2
  • 31
  • 46
  • 3
    In general, I would suggest using an explicit url parser to deal with urls, not regex. See e.g. [URL article on MDN](https://developer.mozilla.org/en-US/docs/Web/API/URL). It seems easier to write/read, and you don't have to deal with (and can't accidentally miss) weird details about url formats. – ASDFGerte Jan 29 '22 at 12:45
  • @ASDFGerte THank you for the answer , but i am looking explicitly for regex match here just to understand how it behaves. I am creating a commadn line utility that takes regex and converts url accordingly – PDHide Jan 29 '22 at 12:48
  • 2
    As your regex starts with a greedy `.*`, and everything behind is optional, the first capture group can always consume everything. I also don't fully understand, why you use `replaceAll`, and a global modifier, when you always only ever operate on a single url, and do a single replace. For learning purposes, there are many regex visualization and testing tools, e.g. https://regex101.com/, https://regexr.com/, or for understanding the automata e.g. https://www.debuggex.com/ – ASDFGerte Jan 29 '22 at 12:53
  • Have you checked [How can I add or update a query string parameter?](https://stackoverflow.com/questions/5999118/how-can-i-add-or-update-a-query-string-parameter)? – Wiktor Stribiżew Jan 29 '22 at 13:15
  • 1
    If you want a really simple solution, you can use `text.replace(/^([^?]*)(?:\?|$)/, '$1?newquery=newvalue&').replace(/&$/, '')` – Wiktor Stribiżew Jan 29 '22 at 13:22
  • @ASDFGerte the question is only part of the whole use case , the user can use any regex to replace anything in the url . say if they pass "test" then all occurance of the word test replaced. Here i want to show the regex to add query parameter to a url using regex – PDHide Jan 29 '22 at 23:11

1 Answers1

0

First let's go through what your regex is doing, then we can fix it. Your regex:

^ - the beginning of the string
(.*) - match any character 0 or more times - as many times as possible (greedy)
[?]? - match `?` 0 or 1 times
(.*) - match any character 0 or more times - as many times as possible (greedy)
$ - the end of the string

Really the main problem here is that the first capturing group captures as many times as possible, so that'll always match the entire url. We can make that non-greedy by using .*?, so we end up with ^(.*?)[?]?(.*)$. However now we end up with the problem that the last capturing group captures the entire url - we could make this non-greedy but then it wouldn't match any characters at all. Instead, we should make sure that this group will only capture when ? is present, so we can make [?]? non-optional, move it into the next capturing group, and make the last group optional, like this: ([?](.*))?. Whilst we're at it, we might as well use \? instead of [?] and we end up with ^(.*?)(\?(.*))?$. This works, as the $ signifies that we want to capture right up to the end. With this we'd need to use $3 instead of $2 as $2 now contains ? as well when replacing, so we can use a non-capturing group to eliminate that problem. So our final regex is /(.*?)(?:\?(.*))?/g.

Your final code will look like this:

let url = "https://test1.com/path?query1=value1"
console.log(url.replaceAll(/^(.*?)(?:\?(.*))?$/g,"$1?newquery=newvalue&$2"))
url = "https://test1.com/path"
console.log(url.replaceAll(/^(.*?)(?:\?(.*))?$/g,"$1?newquery=newvalue&$2"))