How do I loop through a regex's matches inside a replace in javascript?

10,111

Solution 1

Here's the solution that I came up with but it doesn't seem to be very efficient:

$(function () {
    var nestedListFixer = /(?:<\/li><\/ol>\s*)+(?:<p>(?:&(?:nbsp|\#0*160|x0*A0);)+(?:\s[ivxlcdm]+\.)(?:&(?:nbsp|\#0*160|x0*A0);)+\s(.*?)<\/p>\s*)+(?:<ol(?:\sstyle=\"[^\"]+\")?\sstart=\"[^\"]+\">\s*)+/gi;
    var nestedListItem = /<p>(?:&(?:nbsp|\#0*160|x0*A0);)+(?:\s[ivxlcdm]+\.)(?:&(?:nbsp|\#0*160|x0*A0);)+\s(.*?)<\/p>\s*/gi;

    // fix nested lists
    html = html.replace(nestedListFixer, function($0, $1){
        var lis = ""
        $.each($0.match(nestedListItem), function () {
            lis += "<li>" + this.replace(nestedListItem, "$1") + "</li>\n";
        });
        return "<ol>\n" + lis + "</ol></li>";
    });
});

...or for the simpler example above:

$(function () {
    var textFixer = /(?:a)(?:b(.*?)c)+(?:d)/gi;
    var textItem = /b(.*?)c/gi;

    text = text.replace(textFixer, function($0, $1){
        var numbers = "";
        $.each($0.match(textItem), function () {
            numbers += this.replace(textItem, "$1");
        });
        return numbers;
    });
});

Doing a .replace() substitution, inside a loop of a .match() array, inside of a custom .replace() function just doesn't seem like it is very economical. It does give me the output that I was looking for though.

Solution 2

A pretty loop can be using hook pattern :

var text = '1ab2cb3cd4ab5cb6cd7';
text.match(/(\d)/g).forEach(function(element,index){
   console.log(element)
});
Share:
10,111
travis
Author by

travis

Software engineer at Tenet in Rochester, NY. he/him My keybase: keybase.io/trav

Updated on June 05, 2022

Comments

  • travis
    travis almost 2 years

    I have the following JavaScript (the spaces in the <P>s are non-breaking):

    var html = '...<li>sub 2</li></ol></li></ol>\n\
    <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subsub 1</p>\n\
    <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ii.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subsub 2</p>\n\
    <ol start="2"> \n\
    <ol start="3"> \n\
    <li>sub 3</li></ol>...';
    
    $(function () {
        var nestedListFixer = /(?:<\/li><\/ol>\s*)+(?:<p>(?:&(?:nbsp|\#0*160|x0*A0);)+(?:\s[ivxlcdm]+\.)(?:&(?:nbsp|\#0*160|x0*A0);)+\s(.*?)<\/p>\s*)+(?:<ol(?:\sstyle=\"[^\"]+\")?\sstart=\"[^\"]+\">\s*)+/i;
        html = html.replace(nestedListFixer, function($0, $1){
            var lis = ""
            $.each($1, function () {
                lis += "<li>" + this + "</li>\n";
            });
            alert("<ol>\n" + lis + "</ol></li>");
            return "<ol>\n" + lis + "</ol></li>";
        });
    });
    

    The alert()'s output:

    <ol>
    <li>s</li>
    <li>u</li>
    <li>b</li>
    <li>s</li>
    <li>u</li>
    <li>b</li>
    <li> </li>
    <li>2</li>
    </ol></li>
    

    Here's what I hoped it would be:

    <ol>
    <li>subsub 1</li>
    <li>subsub 2</li>
    </ol></li>
    

    How do I correctly loop through each match in the $1?

    Update: simplified pattern and matching example:

    var text = '1ab2cb3cd4ab5cb6cd7';
    
    $(function () {
        var textFixer = /(?:a)(?:b(.*?)c)+(?:d)/i;
        text = text.replace(textFixer, function($0, $1){
            var numbers = "";
            $.each($1, function () {
                numbers += this;
            });
            alert(numbers);
            return numbers;
        });
        alert(text);
    });
    
    // actual text:
    // 13467
    // desired text:
    // 1234567