'How can I exclude the last regex match check on this regex?

How can I match the comma between each key:value pair EXCEPT to exclude the last comma match? And please me know if you have a cleaner regex as mine seems a little messy. I am new to writing regex.

I need to pattern match this format and they need to be map string:string {\"key1\":\"val1\",....N} or {"key1":"val1",....N}

Example

{\"key1\":\"val1\",\"key2\":\"val2\",\"k3\":\"v3\",\"k4\":\"v4\"}

What I have for my regex:

^[{]((["]|[\\]["])[a-zA-Z0-9]+(["]|[\\]["])[:](["]|[\\]["])[a-zA-Z0-9]+(["]|[\\]["])[,])+[}]$

What my match is - I do not want the last comma: {"key1":"val1","key2":"val2","k3":"v3","k4":"v4",}



Solution 1:[1]

Its usually done by requiring the first Key/Val pair, then making all the others
optional with a prepended separator ,

^{\\?"[a-zA-Z0-9]+\\?":\\?"[a-zA-Z0-9]+\\?"(?:,\\?"[a-zA-Z0-9]+\\?":\\?"[a-zA-Z0-9]+\\?")*}$

https://regex101.com/r/cqJk8q/1

 ^ 
 {
 \\? " [a-zA-Z0-9]+ \\? ": \\? " [a-zA-Z0-9]+ \\? "
 (?:
    , \\? " [a-zA-Z0-9]+ \\? ": \\? " [a-zA-Z0-9]+ \\? "
 )*
 }
 $

Solution 2:[2]

Instead of ending with

[,])+[}]$

end with

(,(?!$)|}$))+$

See live demo.

Also, some simplification you can do:

  • [:] is identical to just :, etc for all like this
  • (["]|[\\]["]) is identical to \\?"
  • [a-zA-Z0-9] is almost equivalent to \w (\w also allows the underscore - if that's a problem, just leave [a-zA-Z0-9])

So, your whole regex could be refactored to:

^\{(\\?"\w+\\?":\\?"\w+\\?"(,(?!$)|}$))+$

Your regex however allow mismatched escaping, eg

`{\"key1": "value1"}`
`{"key1": "value1\"}`

To fix that, capture the optional backslash and use a back reference to it on the other end so they must be balanced:

^\{(?:(\\?)"\w+\1":(\\?)"\w+\2?"(,(?!$)|}$))+$

See live demo (with all input varieties).

To also restrict input to either all quotes escaped or no quotes escaped, add negative look ahead anchored to start (?!.*\\".*[^\\]"|.*[^\\]".*\\"), which is one type then the other or visa versa:

^(?!.*\\".*[^\\]"|.*[^\\]".*\\")\{(?:\\?"\w+\\?":\\?"\w+\\?"(,(?!$)|}$))+$

See live demo.

The previous back reference based check for balanced escaping for a key/value pair has been removed because the look ahead now enforces balanced quoting.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 sln
Solution 2