Usr
Usr

Reputation: 2838

Typescript convert string to Map

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?

Upvotes: 0

Views: 7948

Answers (4)

Ayon
Ayon

Reputation: 11

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);

Upvotes: -1

Kunal Mukherjee
Kunal Mukherjee

Reputation: 5853

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}`);
}

Upvotes: 2

tevemadar
tevemadar

Reputation: 13195

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);

Upvotes: 3

VLAZ
VLAZ

Reputation: 29041

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"));

Upvotes: 5

Related Questions