I\'m using JavaScript to do some regular expression. Considering I\'m working with well-formed source, and I want to remove any space before[,.] and keep only one space afte
Do not try to rewrite your expression to do this. You won’t succeed and will almost certainly forget about some corner cases. In the best case, this will lead to nasty bugs and in the worst case you will introduce security problems.
Instead, when you’re already using JavaScript and have well-formed code, use a genuine XML parser to loop over the text nodes and only apply your regex to them.
You can use a lookahead to make sure the match isn't occurring inside a tag:
text = text.replace(/(?![^<>]*>) *([.,]) *([^ \d])/g, '$1 $2');
The usual warnings apply regarding CDATA sections, SGML comments, SCRIPT elements, and angle brackets in attribute values. But I suspect your real problems will arise from the vagaries of "plain" text; HTML's not even in the same league. :D
As stated above and many times before, HTML is not a regular language and thus cannot be parsed with regular expressions.
You will have to do this recursively; I'd suggest crawling the DOM object.
Try something like this...
function regexReplaceInnerText(curr_element) {
if (curr_element.childNodes.length <= 0) { // termination case:
// no children; this is a "leaf node"
if (curr_element.nodeName == "#text" || curr_element.nodeType == 3) { // node is text; not an empty tag like <br />
if (curr_element.data.replace(/^\s*|\s*$/g, '') != "") { // node isn't just white space
// (you can skip this check if you want)
var text = curr_element.data;
text = text.replace(/ *(,|\.) *([^ 0-9])/g, '$1 $2');
curr_element.data = text;
}
}
} else {
// recursive case:
// this isn't a leaf node, so we iterate over all children and recurse
for (var i = 0; curr_element.childNodes[i]; i++) {
regexReplaceInnerText(curr_element.childNodes[i]);
}
}
}
// then get the element whose children's text nodes you want to be regex'd
regexReplaceInnerText(document.getElementsByTagName("body")[0]);
// or if you don't want to do the whole document...
regexReplaceInnerText(document.getElementById("ElementToRegEx"));
Don't parse regexHTML with HTMLregex. If you know your HTML is well-formed, use an HTML/XML parser. Otherwise, run it through Tidy first and then use an XML parser.
If you can access that text through the DOM, you can do this:
function fixPunctuation(elem) {
// check if parameter is a an ELEMENT_NODE
if (!(elem instanceof Node) || elem.nodeType !== Node.ELEMENT_NODE) return;
var children = elem.childNodes, node;
// iterate the child nodes of the element node
for (var i=0; children[i]; ++i) {
node = children[i];
// check the child’s node type
switch (node.nodeType) {
case Node.ELEMENT_NODE:
// call fixPunctuation if it’s also an ELEMENT_NODE
fixPunctuation(node);
break;
case Node.TEXT_NODE:
// fix punctuation if it’s a TEXT_NODE
node.nodeValue = node.nodeValue.replace(/ *(,|\.) *([^ 0-9])/g, '$1 $2');
break;
}
}
}
Now just pass the DOM node to that function like this:
fixPunctuation(document.body);
fixPunctuation(document.getElementById("foobar"));
Html is not a "regular language", therefore regex is not the optimal tool for parsing it. You might be better suited to use a html parser like this one to get at the attribute and then apply regex to do something with the value.
Enjoy!