Reputation: 37
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
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
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