CRafael22
CRafael22

Reputation: 37

Regex to match key=(value, value) format

I'm trying to turn a string with some information about changes in values into an object with these information separated (or an array with them).

The string I receive is something like this format, representing the changes:

{xRate=(250.0, 260.0), yValue=(1.51, 1.54)}.

I would like to get something like

[['xRate', '(250.0, 260.0)'],['yValue', '(1.51, 1.54)']]

or at least have a regex to work since I can't figure it out.

I tried

/,*\s*(.*)=\s*(.*)/

but it creates group 1 as test=(23, 34), var and group 2 as (true , false) in test=(23, 34), var=(true , false), for example.

Thanks in advance for any help!

(Also, if you know any great resource to understand regex more I'd love to see it then I learn this for good haha)

Upvotes: 1

Views: 1023

Answers (2)

Peter Seliger
Peter Seliger

Reputation: 13432

A regex which targets the OP's problem as specific as it was presented through the OP's example code does target up to two key=(value ...) patterns which are enclosed by curly braces ... and might look like this ... /\{\s*(?<key1>[^=\s*]+)\s*=\s*(?<value1>\([^)]+\))\s*(?:,\s*(?<key2>[^=\s*]+)\s*=\s*(?<value2>\([^)]+\))\s*)?\}/g ... but also would equally match ...

  • { key=(value), key=(value, value, ...) }
  • { key=(value, value), key=(value) }
  • { key=(value, value) }
  • { key=(value) }

const sampleText = `{xRate=(250.0, 260.0)  ,  yValue  =(1.51, 1.54)} ... { xRate  =  (250.0, 260.0)  }
... { yValue=(1.51, 1.54) } ... {  xRate = ( 250.0 , 260.0), yValue=(1.51, 1.54) }`;

// [https://regex101.com/r/gJoFH7/1]
const regXKeyValueMaxTwice = (/\{\s*(?<key1>[^=\s*]+)\s*=\s*(?<value1>\([^)]+\))\s*(?:,\s*(?<key2>[^=\s*]+)\s*=\s*(?<value2>\([^)]+\))\s*)?\}/g)

const keyValueToArrayEntryFormat = (match, key1, value1, key2, value2) =>
  (key2 && value2)
    ? `[['${ key1 }', '${ value1 }'], ['${ key2 }', '${ value2 }']]`
    : `[['${ key1 }', '${ value1 }']]`;

console.log(
  sampleText + '\n\n => \n\n',

  sampleText.replace(regXKeyValueMaxTwice, keyValueToArrayEntryFormat)
);

console.log('\nadditional regX logging ...\n\n');

console.log([
  ...sampleText.matchAll(regXKeyValueMaxTwice)
  ]
);
console.log([
  ...sampleText.matchAll(regXKeyValueMaxTwice)
  ].map(({ groups }) => groups)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

But a more generic approach has the freedom of dealing with an unlimited number of key = (value[, value[, ...]]) (sub)pattern sequences wich are all enclosed by curly braces like ... { key=(value), key=(value, value),.. key=(value, value) ... }.

Thus, in order to transform the above format/pattern into ... [["key", "(value)"], ["key", "(value, value)"],.. ["key", "(value, value)"] ...] a regex can not anymore predict the frequency/occurrence of such a base pattern, but it can capture additional flags which allow to later indicate whether such a pattern was opened by { or continued by , or terminated by }.

An also simpler and cleaner regex then might look like this ... /(?<sequenceFlag>[{,])\s*(?<key>\w+)\s*=\s*(?<value>\([^)]+\))\s*(?<terminatingFlag>\}?)/g ... and an implementation of the according replacement then might come close to that ...

const sampleText = `{xRate=(250.0, 260.0)  ,  yValue  =(1.51, 1.54)} ... { xRate  =  (250.0, 260.0)  }

... { yValue=(1.51, 1.54) } ... {  xRate = ( 250.0 , 260.0), yValue=(1.51, 1.54) }

{ xRate = ( 250.0, 260.0 ) ,yValue=(1.51,1.54), zItem =( foo, bar,baz) } ... {xRate=(250.0,260.0)}`;

// [https://regex101.com/r/gJoFH7/2]
const regXKeyValueTemplate = (/(?<sequenceFlag>[{,])\s*(?<key>\w+)\s*=\s*(?<value>\([^)]+\))\s*(?<terminatingFlag>\}?)/g)

const keyValueToArrayEntryFormat = ((match, sequenceFlag, key, value, terminatingFlag) => {
  const concatEntry = (sequenceFlag === '{') && '[[' || ', [';
  const closeSequence = (terminatingFlag === '}') && ']' || '';
  return `${ concatEntry }'${ key }', '${ value }']${ closeSequence }`;
});

console.log(
  sampleText + '\n\n => \n\n',

  sampleText.replace(regXKeyValueTemplate, keyValueToArrayEntryFormat)
);

console.log('\nadditional regX logging ...\n\n');

console.log([
  ...sampleText.matchAll(regXKeyValueTemplate)
  ]
);
console.log([
  ...sampleText.matchAll(regXKeyValueTemplate)
  ].map(({ groups }) => groups)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

regex sources:

Upvotes: 3

Alireza
Alireza

Reputation: 2123

const regex = /(\w+)=\((.+?)\)/g;
const str = `{xRate=(250.0, 260.0), yValue=(1.51, 1.54), test=(23, 34), var=(true , false)}`;
while ((match = regex.exec(str)) !== null) {
  console.log(`first group: ${match[1]} and second: ${match[2]}`);
}

Upvotes: 3

Related Questions