0

I have a string example

"abc|pqr[abc,xyz[abc,def]]"

Now i want to output into array

{
   abc : true,
   pqr : ['abc', xyz : [abc, def]]
}

the code i wrote is this but it give me "message": "Maximum call stack size exceeded"

var x = 'p[a,b,c,d]|q[small,large]|r[small,large]|s|t[w[x,y],z[a,b,c]]';
y = x.split("|");
function foo(query) {
        if (typeof query == "string") query = [query]
        var i = {}
        _(query).forEach(function(v) {
            regexQuery = v.match(/\[(.*)\]/);
            if (regexQuery != null) {
                index = regexQuery['index']
                if (regexQuery[1].match(/\[(.*)\]/) != null) {
                    i[regexQuery['input'].substr(0, index)] = foo(regexQuery[0])
                } else {
                    i[regexQuery['input'].substr(0, index)] = regexQuery[1].split(",");
                }
            } else {
                i[v] = true;
            }
        })
        return i;
    }
console.log(foo(y));

i know regex is not got for this but is there any other solution?

9
  • please add the wanted result of the conversion if x. btw, why is a : necessary and why is it not in the first string abc|pqr[abc,xyz[abc,def]]? Commented Jul 23, 2016 at 11:45
  • 2
    Is there some good reason you're using an invented data structure? Commented Jul 23, 2016 at 11:47
  • I just edited the question removed colon (:), was testing in some different cases @NinaScholz first string only Commented Jul 23, 2016 at 11:59
  • 3
    you first example is no valid javascript. you can not have a property in an array Commented Jul 23, 2016 at 12:03
  • 1
    I really don't understand your example of the before and after. Like @NinaScholz said, it's not valid JavaScript. You have xyz: [abc, def] as one of the elements in the array. Did you mean to wrap that in {} and forget to put quotes around "abc" and "def"? Commented Jul 23, 2016 at 12:36

2 Answers 2

1

You could use the function below. For the input given in the question:

p[a,b,c,d]|q[small,large]|r[small,large]|s|t[w[x,y],z[a,b,c]]

...it produces this object:

{
  "p": [
    "a",
    "b",
    "c",
    "d"
  ],
  "q": [
    "small",
    "large"
  ],
  "r": [
    "small",
    "large"
  ],
  "s": true,
  "t": {
    "w": [
      "x",
      "y"
    ],
    "z": [
      "a",
      "b",
      "c"
    ]
  }
}

function toObject(x) {
    // Turn custom format into JSON text format, and then parse it.
    // In that object, find nested objects that could be turned into array.
    return (function flagsToArray(obj) {
        // Collect keys with nested objects.
        var nested = Object.keys(obj).filter(key => obj[key] !== true);
        // For those, call this function recursively
        nested.forEach(key => obj[key] = flagsToArray(obj[key]));
        // If no nesting, then turn this into an array
        return nested.length ? obj : Object.keys(obj);
    })(JSON.parse('{' + 
        x.replace(/\|/g, ',') // treat '|' as ','
         .replace(/"/g, '\"') // escape any double quotes
         .replace(/([^,|\[\]]+)/g, '"$1"') // wrap terms in double quotes
         .replace(/"\[/g, '":[') // insert colon for assignment of arrays
         .replace(/"([,\]])/g, '":true$1') // insert `true` assignment for atomic term
         .replace(/\[/g, "{").replace(/\]/g, "}") // replace array notation with object notation
        + '}'));
}

// Sample input
var x = 'p[a,b,c,d]|q[small,large]|r[small,large]|s|t[w[x,y],z[a,b,c]]';
// Convert
var obj = toObject(x);
// Output
console.log(obj);

The function makes several replacements to convert the custom format into a JSON text format, turning everything into nested objects (no arrays). Then in a second process, a recursive one, objects are identified that have no nested objects, i.e. they only consist of members with true as value. Those objects are then replaced by their array "equivalent", i.e. the array with the object's keys.

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

Comments

0

Your query string is essentially a flat representation of a tree whose nodes are defined by:

  • either a name alone
  • or a name and a list of child nodes

Note that I don't see any obvious difference between , and |, so I'm going to assume that they actually have the same meaning.

You can't easily store this structure by using only arrays, and it would also be unnecessarily complicated to use a mix of arrays and objects.

Therefore, I'd suggest to use only objects with the following conventions:

  • key = name of node
  • value = either true1 or a child object

1 This is a placeholder. You may also consider using an empty object.

With these assumptions, your example string "abc|pqr[abc,xyz[abc,def]]" would be decoded as:

tree = {
  "abc": true,
  "pqr": {
    "abc": true,
    "xyz": {
      "abc": true,
      "def": true
    }
  }
}

Such a structure is quite easy to manipulate.

For instance, if you'd like to get the child nodes of root > pqr > xyz, you could do:

Object.keys(tree.pqr.xyz)

which will return:

["abc", "def"]

Implementation

Below is a possible implementation:

function parse(query) {
  var n, tree = {}, node = tree, stk = [],
      sym = '', sz = (query += ',').length;

  for(n = 0; n < sz; n++) {
    switch(query[n]) {
      case '|':
      case ',':
        sym && (node[sym] = true);
        break;

      case '[':
        stk.push(node);
        node = node[sym] = {};
        break;

      case ']':
        sym && (node[sym] = true);
        node = stk.pop();
        break;

      default:
        sym += query[n];
        continue;
    }
    sym = '';
  }
  return tree;
}

console.log(parse("abc|pqr[abc,xyz[abc,def]]"));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.