1

I want to parse a string which contains shortcodes and push each extracted node into an array. However the recursive function I have written for this never terminates. What am I doing wrong here?

var i = 0;
var nodes = [];
var pattern = /(\[sc_(\w+)[\s\w="_-]*\])(.*)(\[\/sc_\2\])/gi;

var extractNodes = function(str, parent) {
    var m;

    if (str.indexOf('[sc_') === -1) return;

    while ((m = pattern.exec(str)) !== null) {
        nodes.push({
            id: i,
            tag: m[2],
            children: m[3],
            parentId: parent
        });
        extractNodes(m[3], i++);
    }
}

extractNodes("[sc_div][sc_span][sc_strong]Foo[/sc_strong][/sc_span][/sc_div]", -1); 
4
  • 2
    can you tell us what the output would be for your example here? Commented Apr 4, 2016 at 1:59
  • 2
    Missed return in the recursive function. return extractNodes(m[3], i++); Commented Apr 4, 2016 at 2:02
  • @Tushar return doesn't seem to be the issue. There is something about the regex, its sending the same str parameter for every iteration: jsfiddle.net/igor_9000/9yaz6cdu Commented Apr 4, 2016 at 2:11
  • 1
    @AdamKonieska Right! The code is missing break Commented Apr 4, 2016 at 2:23

1 Answer 1

1

You've got a conflict between your while loop and the global (g flag) RegEx.

Each iteration of the function is sending the same str parameter. You can fix this by making the RegEx non-global by removing the g flag and while loop.

Live Demo

var i = 0;
var nodes = [];
var pattern = /(\[sc_(\w+)[\s\w="_-]*\])(.*)(\[\/sc_\2\])/i; // <-- Remove `g` flag

var extractNodes = function (str, parent) {
    var m;
    if (str.indexOf('[sc_') === -1) return;

    if ((m = pattern.exec(str)) !== null) {
        nodes.push({
            id: i,
            tag: m[2],
            children: m[3],
            parentId: parent
        });

        extractNodes(m[3], i++);
    }
}

extractNodes("[sc_div][sc_span][sc_strong]Foo[/sc_strong][/sc_span][/sc_div]", -1);
console.log(nodes);

document.body.innerHTML = '<pre>' + JSON.stringify(nodes, 0, 4) + '</pre>'; // For DEMO purpose only

Console Output (Chrome):

[Object, Object, Object]
0:Object
  children: "[sc_span][sc_strong]Foo[/sc_strong][/sc_span]"
  id: 0
  parentId: -1
  tag: "div"
  __proto__: Object
1:Object
  children: "[sc_strong]Foo[/sc_strong]"
  id: 1
  parentId: 0
  tag: "span"
  __proto__: Object
2:Object
  children: "Foo"
  id: 2
  parentId: 1
  tag: "strong"
  __proto__: Object
length: 3
__proto__: Array[0]

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

2 Comments

Thanks for your reply. But this won't work when there are siblings. Imagine the following input: [sc_div][sc_span][sc_strong]Foo[/sc_strong][/sc_span][/sc_div] [sc_div][sc_span][sc_strong]Bar[/sc_strong][/sc_span][/sc_div]
@coder9 Make the regex non-greedy by using ? (\[sc_(\w+)[\s\w="_-]*\])(.*?)(\[\/sc_\2\])

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.