How do I loop through a regex's matches inside a replace in javascript?
-
12-09-2019 - |
Question
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> i. subsub 1</p>\n\
<p> ii. 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
Solution 2
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.
OTHER TIPS
The updated example you've given would only match "3" not "13467" as you described. If you change your regexp to do global matching, it would return "36" and still not the "13467".
Your first example doesn't output anything either.
Are you just trying to get matches to the regular expression and loop through the matches?
If so,
var text = '1ab2cb3cd4ab5cb6cd7';
var matches = text.match(/(\d)/g);
for (i=0; i<matches.length; i++) {
alert(matches[i]);
}
A pretty loop can be using hook pattern :
var text = '1ab2cb3cd4ab5cb6cd7';
text.match(/(\d)/g).forEach(function(element,index){
console.log(element)
});