1

I just used regex101, to create the following regex.

([^,]*?)=(.*?)(?(?=, )(?:, )|(?:$))(?(?=[^,]*?=)(?:(?=[^,]*?=))|(?:$))

It seems to work perfectly for my use case of getting keys and values that are comma separated while still preserving commas in the values.

Problem is, I want to use this Regex in Node.js (JavaScript), but while writing this entire Regex in regex101, I had it set to PCRE (PHP).

It looks like JavaScript doesn't support Conditional Lookaheads ((?(?=...)()|()).

Is there a way to get this working in JavaScript?


Examples:

2 matches

group 1: id, group 2: 1

group 1: name, group 2: bob

id=1, name=bob

3 matches

group 1: id, group 2: 2

group 1: type, group 2: store

group 1: description, group 2: Hardwood Store

id=2, type=store, description=Hardwood Store

4 matches

group 1: id, group 2: 4

group 1: type, group 2: road

group 1: name, group 2: The longest road name, in the entire world, and universe, forever

group 1: built, group 2: 20190714

id=4, type=road, name=The longest road name, in the entire world, and universe, forever, built=20190714

3 matches

group 1: id, group 2: 3

group 1: type, group 2: building

group 1: builder, group 2: Random Name, and Other Person, with help from Final Person

id=3, type=building, builder=Random Name, and Other Person, with help from Final Person

3 Answers 3

1

You may use

/([^,=\s][^,=]*)=(.*?)(?=(?:,\s*)?[^,=]*=|$)/g

See the regex demo.

Details

  • ([^,=\s][^,=]*) - Group 1:
    • [^,=\s] - a char other than ,, = and whitespace
    • [^,=]* - zero or more chars other than , and =
  • = - a = char
  • (.*?) - Group 2: any zero or more chars other than line break chars, as few as possible
  • (?=(?:,\s*)?[^,=]*=|$) - a positive lookahead that requires an optional sequence of , and 0+ whitespaces and then 0+ chars other than , and = and then a = or end of string immediately to the right of the current location

JS demo:

var strs = ['id=1, name=bob','id=2, type=store, description=Hardwood Store', 'id=4, type=road, name=The longest road name, in the entire world, and universe, forever, built=20190714','id=3, type=building, builder=Random Name, and Other Person, with help from Final Person']
var rx = /([^,=\s][^,=]*)=(.*?)(?=(?:,\s*)?[^,=]*=|$)/g;
for (var s of strs) {
   console.log("STRING:", s);
   var m;
   while (m=rx.exec(s)) {
     console.log(m[1], m[2])
   }
} 

Sign up to request clarification or add additional context in comments.

2 Comments

This works really well! Thanks for the detailed explanation. Only problem, is I realized that some of the values have = signs in them as well. So now I have to figure out a way to ensure there is a comma before the =, or else it's part of the value. For example id=1, url=https://test.com/hello/world?name=bob, random=5. 3 matches here. id & 1, url & https://test.com/hello/world?name=bob, random & 5.
@CharlieFish I thought the comma and spaces are optional. If not use regex101.com/r/5fFQV5/3
0

Maybe, these expressions would be somewhat close to what you might want to design:

([^=\n\r]*)=\s*([^=\n\r]*)\s*(?:,|$)

or

\s*([^=\n\r]*)=\s*([^=\n\r]*)\s*(?:,|$)

not sure though.

DEMO


The expression is explained on the top right panel of this demo if you wish to explore/simplify/modify it.

const regex = /\s*([^=\n\r]*)=\s*([^=\n\r]*)\s*(?:,|$)/gm;
const str = `id=3, type=building, builder=Random Name, and Other Person, with help from Final Person

id=4, type=road, name=The longest road name, in the entire world, and universe, forever, built=20190714

id=2, type=store, description=Hardwood Store
id=1, name=bob

`;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}

RegEx Circuit

jex.im visualizes regular expressions:

enter image description here

Comments

0

Yet another way to do it

\s*([^,=]*?)\s*=\s*((?:(?![^,=]*=)[\S\s])*)(?=[=,]|$)

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

Readable version

 \s* 
 ( [^,=]*? )                   # (1), Key
 \s* = \s*                     #       =
 (                             # (2 start), Value
      (?:
           (?! [^,=]* = )
           [\S\s] 
      )*
 )                             # (2 end)
 (?= [=,] | $ )

Ultimate PCRE version

\s*([^,=]*?)\s*=\s*((?:(?!\s*[^,=]*=)[\S\s])*(?<![,\s]))\s*(?=[=,\s]|$)

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

 \s*                           # Wsp trim
 ( [^,=]*? )                   # (1), Key
 \s* = \s*                     # Wsp trim =  Wsp trim
 (                             # (2 start), Value
      (?:
           (?! \s* [^,=]* = )
           [\S\s] 
      )*
      (?<! [,\s] )                  # Wsp trim
 )                             # (2 end)
 \s*                           # Wsp trim
 (?= [=,\s] | $ )              # Field seperator

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.