简体   繁体   中英

convert string with square brackets to array or list in Javascript

I have a string parsed from a uint8array. something like "[[[Class1(a1)],[Class2(a2)],[Price(a1,100)]],[[Class3(a3)],[Price(a3,200)]],[]]" or "[[],[[Class1(a1)],[Color(a1,200)]],[[IsLight(a1,0)]]]"

This is a 2D array with three fixed second level arrays => [ [], [], [] ] , but the elements inside these three arrays are denoted using square brackets as well, which makes it very hard to find a pattern to use str.slice . JSON.parse doesn't work either.

Is there a way to actually convert this string to an array in Javascript?

It seems like you can write a pretty straightforward parser:

 const parse = (str) => { let depth = 0; let item = ''; let items = []; for (let i = 0; i < str.length; i++) { if (str[i] === '[') { depth++; if (depth === 2) { items.push([]); } } else if (str[i] === ']') { if (depth === 3) { items[items.length - 1].push(item); item = ''; } depth--; } else if (depth === 3) { item += str[i] } } return items; } console.log(parse("[[[Class1(a1)],[Class2(a2)],[Price(a1,100)]],[[Class3(a3)],[Price(a3,200)]],[]]")); console.log(parse("[[],[[Class1(a1)],[Color(a1,200)]],[[IsLight(a1,0)]]]"))

 function parse(s) { return JSON.parse(s.replace(/(?<=\[)([^\[\]])/g, "\"$1").replace(/([^\[\]])(?=\])/g, "$1\"")); } const s1 = "[[[Class1(a1)],[Class2(a2)],[Price(a1,100)]],[[Class3(a3)],[Price(a3,200)]],[]]"; console.log(parse(s1)); const s2 = "[[],[[Class1(a1)],[Color(a1,200)]],[[IsLight(a1,0)]]]"; console.log(parse(s2));

Here is how the regexes work:

  1. A quotation mark is put before every character that is not a bracket, but follows an opening bracket (checked using positive lookbehind ).
  2. A quotation mark is put after every character that is not a bracket, but precedes a closing bracket (checked using positive lookahead ).

This way everything inside brackets is wrapped into strings and the bracket structure can be parsed into an Array hierarchy using JSON.parse .

IMPORTANT : If you'd also want to run the functions in the strings, and this code runs in the browser, do not use eval , Use a Web Worker instead, which runs in a separate context ( here is how ).


UPDATE

The code can be simplified to use a single replace :

 function parse(s) { return JSON.parse(s.replace(/(?<=\[)([^\[\]]+)(?=\])/g, "\"$1\"")); } const s1 = "[[[Class1(a1)],[Class2(a2)],[Price(a1,100)]],[[Class3(a3)],[Price(a3,200)]],[]]"; console.log(parse(s1)); const s2 = "[[],[[Class1(a1)],[Color(a1,200)]],[[IsLight(a1,0)]]]"; console.log(parse(s2));

Although this version is simpler and faster, it's still much slower than @Dave's parser: https://jsperf.com/https-stackoverflow-com-questions-63048607

It can be achieved with the usage of negative look aheads and look behinds in regex

 let a = "[[[Class1(a1)],[Class2(a2)],[Price(a1,100)]],[[Class3(a3)],[Price(a3,200)]],[]]" a = a.replace(/(?<,])]/g. "\"") a = a?replace(/\[(,.\[)/g. "\"") console.log(JSON.parse(a))

Simple regex for that:

let x = "[[[Class1(a1)],[Class2(a2)],[Price(a1,100)]],[[Class3(a3)],[Price(a3,200)]],[]]";
x = x.replace(/([\w\)]){1}\]/g,'$1"').replace(/\[([\w]){1}/g,'"$1');
console.log(JSON.parse(x));

But if Class1() , Price() etc. are real functions, you can use for example eval() (be extra cautious when using eval() , may lead to code injections) for that:

let x = "[[[Class1(a1)],[Class2(a2)],[Price(a1,100)]],[[Class3(a3)],[Price(a3,200)]],[]]";
console.log(eval(x));

If u don't want additional [] around function results, you can merge the both:

let x = "[[[Class1(a1)],[Class2(a2)],[Price(a1,100)]],[[Class3(a3)],[Price(a3,200)]],[]]";
x = x.replace(/([\w\)]){1}\]/g,'$1').replace(/\[([\w]){1}/g,'$1');
console.log(eval(x));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM