-1

I was trying to get rid of empty attribute groups from the following string.

var str = '{"groups":[{"groupId":"03V5DCC","attributes":{}},{"groupId":"02VXTCB","attributes":{"registrationId":"550049390"}},{"groupId":"W3UV5SD","attributes":{}},],"status":{"code":200,"messageResource":"string-serverres-success"}}';

// tried with g and without g 
console.log(str.replace(/\{"groupId":".*?","attributes":\{\}\},/g,''));
// Output: "{"groups":[],"status":{"code":200,"messageResource":"string-serverres-success"}}"

console.log(str.replace(/\{"groupId":".*?","attributes":\{\}\},/,''));
// Output: "{"groups":[{"groupId":"02VXTCB","attributes":{"registrationId":"550049390"}},{"groupId":"W3UV5SD","attributes":{}},],"status":{"code":200,"messageResource":"string-serverres-success"}}"
.as-console-wrapper {
    max-height: 100% !important;
}

The one with global becomes greedy and removes groups even with attribute and the other one without g is just removing the first match. Since the JSON is quite big in size(~10mb) parsing is not an option for me before reducing the string size.

sanjay patel
  • 449
  • 8
  • 17
  • 3
    If this is always going to be valid JSON (as it seems like here), then why not parse -> manipulate -> serialise? – VLAZ Jan 23 '20 at 15:49
  • 2
    The lesson here is: Don't try to parse recursive structures with simple regular expressions on their own. It doesn't work. [Like HTML](https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags#1732454)... – T.J. Crowder Jan 23 '20 at 15:51
  • Note: Both of your examples do exactly the same thing and produce exactly the same result, since there's only one match. The first one does not output what you said they output. I've put your code into a snippet, you can see the results. – T.J. Crowder Jan 23 '20 at 15:53
  • I have just edited the question adding, this is just an example, my JSON string size is around 10mb, so I am planning to remove empty attribute first before parsing it. – sanjay patel Jan 23 '20 at 15:54
  • @sanjaypatel uh...you could do it *during* parsing – VLAZ Jan 23 '20 at 15:56
  • TJ You are right, I missed one comma in str initialization.Thank you for pointing that out, I fixed it. Now the JSON is imperfect, which should be fine as I am not looking to use JSON.parse. – sanjay patel Jan 23 '20 at 16:12

2 Answers2

0

The non-greedy .*? is in fact not greedy, but it will consume characters until whatever follows it does match. Thus if there's a group with non-empty attributes, that will not satisfy the match, so the .*? will continue to "eat" characters in the string until it finds a match.

As others have noted, don't do it this way. Parse the string as JSON and then operate on the data structure itself. If you need it as JSON afterwards, re-serialize it with JSON.stringify().

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Pointy, you are right, but still I am not able to pull it out. Is it achievable what I am looking for with regex? I want to understand what is the regex way to achieve it not the JSON parse way. – sanjay patel Jan 23 '20 at 16:18
0

You can remove the properties as you are parsing if you use the optional reviver parameter of JSON.parse. It's a function that will run against each key-value pair and can modify or drop values as the parsing algorithm goes. So, you can watch for a key of attributes and check if the value is an empty object. If so, return undefined from the reviver and that key-value pair will be discarded. Otherwise, just proceed as normal:

var str = '{"groups":[{"groupId":"03V5DCC","attributes":{}},{"groupId":"02VXTCB","attributes":{"registrationId":"550049390"}},{"groupId":"W3UV5SD","attributes":{}}],"status":{"code":200,"messageResource":"string-serverres-success"}}';


var obj = JSON.parse(str, function (key, value) {

    //if the key is `attribute` and the value is empty, then drop it
    if (key === "attributes" && isEmpty(value)) 
      return undefined;

    //just return the value
    return value;
  }
)

//sample implementation of a check for empty objects
function isEmpty(obj) {
  return Object.keys(obj).length === 0;
}

console.log(obj);
VLAZ
  • 26,331
  • 9
  • 49
  • 67