Reputation: 35
I want to replace the words "red" and "td" with "blue" in the content below, but I don't want the color attribute of the last <td>
and all the <td>
tag to be messed.
<tr>
<td>Code name td A001</td>
<td>Madam Red</td>
<td><font color="red">do your job</font></td>
</tr>
This is what I want:
<tr>
<td>Code name blue A001</td>
<td>Madam blue</td>
<td><font color="red">do your job</font></td>
</tr>
But I got this result when I use /<td>.*(red|td).*<\/td>/gi
to replace the content.
<tr>
<blue>Code name blue A001</blue>
<blue>Madam blue</blue>
<blue><font color="blue">do your job</font></blue>
</tr>
Are there any regex to solve this problem?
Thanks.
Upvotes: 1
Views: 87
Reputation: 50797
Do note the link Scott Kaye posted. Regex is not a good tool for parsing or manipulating HTML.
I created a Fiddle which demonstrated a very different approach. Mine involves a very minimal DOM walker. You supply it a node and it walks the DOM starting at that node calling back to your functions with the various nodes it visits. The DOM Walker implementation is just thrown together, and I'm sure it is in vast need of improvement, but it works for this case. You would call it like this:
var dw = new DomWalker();
dw.on('text', function(node) {
node.nodeValue = node.nodeValue.replace(/red|td/ig, 'blue');
});
dw.walk(document.getElementById('myRow'));
Note that although I'm still using regex here, I'm only doing so on plain text strings.
If nothing else, it should give you an alternative to try.
Upvotes: 0
Reputation: 626903
Here is a trick that allows replacing with just 1 go:
((?!<\/td)[^<]|^)(?:td|red)(?![^<]*>)
Replace with
$1blue
See demo.
Sample code:
var re = /((?!<\/td)[^<]|^)(?:td|red)(?![^<]*>)/ig;
var str = '<tr>\n <td>Code /td name td A001</td>\n <td>Madam Red</td>\n <td><font color="red">do your job</font></td>\n</tr>';
var subst = '$1blue';
var result = str.replace(re, subst);
Result:
<tr>
<td>Code /blue name blue A001</td>
<td>Madam blue</td>
<td><font color="red">do your job</font></td>
</tr>
Upvotes: 2
Reputation: 5271
This is a hack, but it works. It requires a few iterations of replacements.
Step 1: add markers to text in any places where there's a tag OR your target words (td or red). Only tags are put back in the replacement; the target words are omitted, replaced by just the marker itself.
Search: (<[^>]+>)|(\btd\b|\bred\b)
Replace: $1@MARKER@
Temporary Result:
<tr>@MARKER@
<td>@MARKER@Code name @MARKER@ A001</td>@MARKER@
<td>@MARKER@Madam @MARKER@</td>@MARKER@
<td>@MARKER@<font color="red">@MARKER@do your job</font>@MARKER@</td>@MARKER@
</tr>@MARKER@
Step 2: remove (from resulting string) markers that matched tags
Search: (<[^>]+>)@MARKER@
Replace: $1
Temporary Result:
<tr>
<td>Code name @MARKER@ A001</td>
<td>Madam @MARKER@</td>
<td><font color="red">do your job</font></td>
</tr>
Step 3: replace (from resulting string) any remaining markers with "blue"
Search: @MARKER@
Replace: blue
Upvotes: -1