1

i am working in a opensource proyect. It basically generate json response from query string.

The bug.

I was testing the project and i found bug in a regex (were i am not god :( )

This is the regex that i am using.

            (?:(\{).*?(\})|[^,])+

Basically it split the string when match the pattern Example.

        // string example
        a:{anyhing},b:{anything},c:{anything}

        // expected
        [
            "a:{anyhing}",
            "b:{anything}",
            "c:{anything}"
        ]

Case 1. Success The string that i am passing

            "a:{m:st,n:{x:st}},b:{m:st}"

Expected result: succcess

            [
                "a:{m:st,n:{x:st}}",
                "b:{m:st}"
            ]

Case 2. Fail The string that i am passing

            "a:{n:{x:st},m:st},b:{m:st}"

Unexpected result

            [
                "a:{n:{x:st}",
                "m:st}",
                "b:{m:st}",
            ]               

Expected result: should be like Case 1

            [
                "a:{n:{x:st},m:st}",
                "b:{m:st}"
            ]

Thank you.

Feel free to read about the project here https://github.com/rollrodrig/customjsonbuilder and here https://www.npmjs.com/package/customjsonbuilder

Edit:

The string could have hell nested {} like this

            // string
            "a:{m: {x:str,y:str}, n:str },b:{m:str,n:str},c:{t:string}"
            // expected
            [
                "a:{m: {x:str,y:str}, n:str }",
                "b:{m:str,n:str}",
                "c:{t:string}",
            ]

            // string
            "a:{m: {x:{d:str,i:str},y:str}, n:str },b:{m:str,n:str},c:{t:string}"
            // expected
            [
                "a:{m: {x:{d:str,i:str},y:str}, n:str }",
                "b:{m:str,n:str}",
                "c:{t:string}"
            ]

            // string
            "a:{n:{x:{h:{i:string},x:{d:string}}},m:{h:string}},b:{k:string,l:{u:str,r:str}},c:{t:string}"
            // expected
            [
                "a:{n:{x:{h:{i:string},x:{d:string}}},m:{h:string}}",
                "b:{k:string,l:{u:str,r:str}}",
                "c:{t:string}"
            ]
Rolly
  • 2,375
  • 1
  • 17
  • 28
  • 1
    see: https://stackoverflow.com/questions/546433/regular-expression-to-match-balanced-parentheses and https://stackoverflow.com/questions/133601/can-regular-expressions-be-used-to-match-nested-patterns – Mark Jun 10 '19 at 20:59
  • 4
    Regular expressions, and the Javascript flavor especially, are not suitable for recursive structures. You need a proper stack-based parser here. – georg Jun 10 '19 at 20:59
  • @georg What exactly is stack-based? – Rolly Jun 11 '19 at 01:14

1 Answers1

0

Well, after somethinking i decided to change the code. This time i decided to not use regex.

            export const comaDivider = (string:string) => {
                let braces:number = 0;
                let indexes:number[] = [];
                let divided:string[] = [];
                let l = string.length;
                for (let i = 0; i < l; i++) {
                    let c = string.charAt(i);
                    if(c === "{")
                        braces++;
                    if(c === "}")
                        braces--;
                    if(c === "," && braces === 0) 
                        indexes.push(i);
                }
                indexes.push(string.length);
                indexes.reduce((prev:number,next:number)=>{
                    divided.push(string.substring(prev,next));
                    return next+1;
                },0)
                return divided;
            }

The unit test passed succesfully

            it('run', () => {
                expect(comaDivider("name:string,email:string"))
                    .to.deep.equal(["name:string","email:string"]);
                expect(comaDivider("name:string,nicks:{first:string,last:string}"))
                    .to.deep.equal(["name:string","nicks:{first:string,last:string}"]);
                expect(comaDivider("name:string,email:string,nicks:{first:string,last:string}"))
                    .to.deep.equal(["name:string","email:string","nicks:{first:string,last:string}"]);
                expect(comaDivider("name:string,nicks:{first:string,last:string},email:string"))
                    .to.deep.equal(["name:string","nicks:{first:string,last:string}","email:string"]);
                expect(comaDivider("name:string,nicks:{first:string,last:{year:number,age:23}},email:string"))
                    .to.deep.equal(["name:string","nicks:{first:string,last:{year:number,age:23}}","email:string"]);
                expect(comaDivider("name:string,nicks:[{first:string,last:string}]"))
                    .to.deep.equal(["name:string","nicks:[{first:string,last:string}]"]);
                expect(comaDivider("name:string,nicks:[{first:string,last:string};10]"))
                    .to.deep.equal(["name:string","nicks:[{first:string,last:string};10]"]);
                expect(comaDivider("name:string,nicks:[{first:string,last:[{name:string, age:23};5]};10],other:string"))
                    .to.deep.equal(["name:string","nicks:[{first:string,last:[{name:string, age:23};5]};10]","other:string"]);
                expect(comaDivider("name:string,nicks:{first:string,last:[{name:string, age:23};5]},other:string"))
                    .to.deep.equal(["name:string","nicks:{first:string,last:[{name:string, age:23};5]}","other:string"]);
            });

            it('fixing bug', () => {
                let r1 = [];
                r1 = comaDivider("a:string,b:string");
                expect(r1).to.deep.equal(["a:string","b:string"])
                r1 = comaDivider("a:string,b:string,c:string");
                expect(r1).to.deep.equal(["a:string","b:string","c:string"])
                r1 = comaDivider("a:{m:{x:string},n:strin},b:string");
                expect(r1).to.deep.equal(["a:{m:{x:string},n:strin}","b:string"])
                r1 = comaDivider("a:{n:strin,m:{x:string}},b:string");
                expect(r1).to.deep.equal(["a:{n:strin,m:{x:string}}","b:string"])
                r1 = comaDivider("b:{x:{n:string},y:{m:string}},a:string");
                expect(r1).to.deep.equal(["b:{x:{n:string},y:{m:string}}","a:string"])
                r1 = comaDivider("b:{x:{n:string},y:{m:string,h:{t:string,r:string}}},a:string");
                expect(r1).to.deep.equal(["b:{x:{n:string},y:{m:string,h:{t:string,r:string}}}","a:string"])
                r1 = comaDivider("b:{x:{n:string}},y:{m:string},a:string");
                expect(r1).to.deep.equal(["b:{x:{n:string}}","y:{m:string}","a:string"])
                r1 = comaDivider("b:{x:{n:string},y:{m:string,h:{t:string,r:string}}},a:string");
                expect(r1).to.deep.equal(["b:{x:{n:string},y:{m:string,h:{t:string,r:string}}}","a:string"])
                r1 = comaDivider("y:string,b:{x:{n:string},y:string},a:{s:{d:string}}");
                expect(r1).to.deep.equal(["y:string","b:{x:{n:string},y:string}","a:{s:{d:string}}"])
                r1 = comaDivider("b:string,c:{m:string,n:string},d:string");
                expect(r1).to.deep.equal(["b:string","c:{m:string,n:string}","d:string"])
                r1 = comaDivider("b:{x:string,y:{y:string,w:num}},c:{m:string,n:string},d:string,f:{h:num,r:str},to:{na:str}");
                expect(r1).to.deep.equal(["b:{x:string,y:{y:string,w:num}}","c:{m:string,n:string}","d:string","f:{h:num,r:str}","to:{na:str}"])
            })

If any one have an improvement for this code just let me know.

Rolly
  • 2,375
  • 1
  • 17
  • 28