0

I have this string (called currentExecution.variables):

{executionid=0c3246fb37e65e3368c8c4f30000016ab593bec244daa8df, timeout=10000}

and I need to convert it into a Map so that I can work with the entries, but I'm having a hard time doing this. I've tried, following this answer, to transform it into a key-value set of pairs. First I've replaced = with : and { or } with white space, then splitted it according to the answer:

newString.split(/,(?=[^,]+:)/).map(s => s.split(': '));

but I do not get the proper result, and I'm stuck without the Map. What's missing? Or is there a better/faster way to do this?

6
  • Assuming that the first part works: you have '=' to split around, not ': ' (especially not with the space). Commented May 14, 2019 at 9:59
  • Why? If I have replaced = with :, I can't split around = Commented May 14, 2019 at 10:01
  • 1
    I said that I've replaced my = with :. So the resulting string would be the same as the original but with : instead of =. Then on this string I do the split. Commented May 14, 2019 at 10:11
  • @Dseaster You are right, I missed that part. Commented May 14, 2019 at 10:11
  • @Dseaster Map as in the Map object, or Map as in just an object, like what parsed json would churn out? Commented May 14, 2019 at 10:15

4 Answers 4

5

You can do the following

  1. Removing the { and } characters from the start and end the string. Do not use replace in case there are any occurrences inside it.
  2. Split the result into each discrete chunk that forms key-value pairs.
  3. Split those into actual key and value
  4. The result can readily be convert to a Map because the constructor takes an array where each item is an array with two items and will convert that to a map where the first item is the key, the second the value:

let string = "{executionid=0c3246fb37e65e3368c8c4f30000016ab593bec244daa8df, timeout=10000}";

let keyValuePairs = string.slice(1, -1) //remove first and last character
  .split(/\s*,\s*/)                     //split with optional spaces around the comma
  .map(chunk => chunk.split("="));      //split key=value
  
const map = new Map(keyValuePairs);

console.log(map.get("executionid"));
console.log(map.get("timeout"));

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

2 Comments

Thank you, that's what I meant. Does this solution work with a random number of key=value pairs in String?
@Dseaster yes, it works with any amount of key-value pairs. You might have a problem if a value includes a comma , or if it includes an equals sign = - in those cases the split might turn out wrong.
3

You can work without regexps too, but you have to understand the basic concept of that first you split along the ,s, and then along the =s:

var data = "{executionid=0c3246fb37e65e3368c8c4f30000016ab593bec244daa8df, timeout=10000}";
var pairs = data.substring(1, data.length - 1).split(", "); // step 1, split using commas

var obj = pairs.reduce(function(acc, cur) {
  var pair = cur.split("="); // step 2, split using =
  acc[pair[0].trim()] = pair[1].trim();
  return acc;
}, {});

console.log(obj);

6 Comments

For me it is right, even if it doesn't return a Map. Don't know why it was considered wrong.
Yeah, I think somebody just serially downvoted everything here. It's not wrong - I was actually going to add a section for using an object but you beat me to it.
@Dseaster yes, it was the guy who deleted his answer I think.
Apparently the user started to downvoting all my past questions. Do you remember his username? I can't find him anymore.
@Dseaster there is a mechanism which will probably revert it later: meta.stackexchange.com/questions/126829/… - so check your history tomorrow.
|
2

You can capture the key and value pairs in a capturing group shown in this regex.

Based on that you can go ahead and reduce its value to a Map.

const currentExecutionVariable = "{executionid=0c3246fb37e65e3368c8c4f30000016ab593bec244daa8df, timeout=10000}";

const pattern = /([A-Za-z0-9]+)\=([A-Za-z0-9]+)/g;

const matches = currentExecutionVariable.match(pattern);

const currentExecutionMap = matches.reduce((acc, curr) => {
	const [key, value] = curr.split('=');
	
	if (!acc.has(key)) {
		acc.set(key, value);
	}	
	return acc;
}, new Map());

for (const [key, value] of currentExecutionMap.entries()) {
  console.log (`${key}: ${value}`);
}


Update

Using the captured groups:

const currentExecutionVariable = "{executionid=0c3246fb37e65e3368c8c4f30000016ab593bec244daa8df, timeout=10000}";

const pattern = /([A-Za-z0-9]+)\=([A-Za-z0-9]+)/g;

let currentExecutionMap = new Map();

let capturedGroup;
while ((capturedGroup = pattern.exec(currentExecutionVariable))) {

  // 1st captured group is the key of the map
  const key = capturedGroup[1];

  // 2nd captured group is the value of the map
  const value = capturedGroup[2];

  if (!currentExecutionMap.has(key)) {
    currentExecutionMap.set(key, value);
  }
}

for (const [key, value] of currentExecutionMap.entries()) {
  console.log(`${key}: ${value}`);
}

2 Comments

You don't need to escape = in the regex - there is no special meaning to the character. Also, the .reduce is not strictly needed, since you can just do new Map([["key1", "value1"], ["key2", "value2"]]) to populate the map. Still, these are minor points - good solution. The actual improvement I'd suggest is using the capture groups from the regex - doing pattern.exec(currentExecutionVaruable) will give the key and value captured, do you don't need to split the result. while(result = pattern.exec(currentExecutionVaruable)) map.set(result[1], result[2])`
@VLAZ I think the splitting of = is unnecessary, I will update my answer
-1

I have this string (called stats):

active_total: 1087
cumulative: 1
trace_total: 10

which is not even in JSON format.

This is the solution that I am trying:

let keyValuePairs = stats
  .split(/\s*\n\s*/)                     //split with optional spaces around the comma
  .map(chunk => chunk.split(": "));      //split key=value
  
const map = new Map(keyValuePairs);

console.log(map.get("sessions_active_total"));
console.log(map.get("cumulative"));

But it is throwing compilation error at this line:

const map = new Map(keyValuePairs);

Error message:

error TS2769: No overload matches this call.
  Overload 1 of 3, '(iterable: Iterable<readonly [unknown, unknown]>): Map<unknown, unknown>', gave the following error.
    Argument of type 'string[][]' is not assignable to parameter of type 'Iterable<readonly [unknown, unknown]>'.
      The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
        Type 'IteratorResult<string[], any>' is not assignable to type 'IteratorResult<readonly [unknown, unknown], any>'.
          Type 'IteratorYieldResult<string[]>' is not assignable to type 'IteratorResult<readonly [unknown, unknown], any>'.
            Type 'IteratorYieldResult<string[]>' is not assignable to type 'IteratorYieldResult<readonly [unknown, unknown]>'.
              Type 'string[]' is not assignable to type 'readonly [unknown, unknown]'.
                Target requires 2 element(s) but source may have fewer.
  Overload 2 of 3, '(entries?: readonly (readonly [unknown, unknown])[]): Map<unknown, unknown>', gave the following error.
    Argument of type 'string[][]' is not assignable to parameter of type 'readonly (readonly [unknown, unknown])[]'.
      Type 'string[]' is not assignable to type 'readonly [unknown, unknown]'.

58         const map = new Map(keyValuePairs);

1 Comment

This falls under the category of a question, posting this as an answer to someone else's question is totally wrong. Ask a new question to draw more attention to your question and others will do their best to answer it. Cheers and welcome to SO!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.