正则表达式只搜索/替换文本,而不是HTML属性

时间:2010-08-11 15:24:48

标签: javascript html regex

我正在使用JavaScript来做一些正则表达式。考虑到我正在使用格式良好的源,我想在[,。]之前删除任何空格,并且在[,。]之后只保留一个空格,除了[,。]是数字的一部分。因此我使用:

text = text.replace(/ *(,|\.) *([^ 0-9])/g, '$1 $2');

问题是,这也取代了html标记属性中的文本。例如,我的文字是(总是用标签包裹):

<p>Test,and test . Again <img src="xyz.jpg"> ...</p>

现在它添加了一个不期望的src="xyz. jpg"这样的空间。我怎样才能重写我的正则表达式?我想要的是

<p>Test, and test. Again <img src="xyz.jpg"> ...</p>

谢谢!

6 个答案:

答案 0 :(得分:4)

您可以使用前瞻来确保标记内没有匹配:

text = text.replace(/(?![^<>]*>) *([.,]) *([^ \d])/g, '$1 $2');

通常的警告适用于CDATA部分,SGML注释,SCRIPT元素和属性值中的尖括号。但我怀疑你的真正问题会出现在“普通”文本的变幻莫测之中; HTML甚至不在同一个联盟中。 :d

答案 1 :(得分:1)

不要尝试重写表达式来执行此操作。你不会成功,几乎肯定会忘记一些角落案件。在最好的情况下,这将导致令人讨厌的错误,在最坏的情况下,您将引入安全问题。

相反,当您已经使用JavaScript并且具有格式良好的代码时,请使用真正的XML解析器循环文本节点,并仅将正则表达式应用于它们。

答案 2 :(得分:1)

如果您可以通过DOM访问该文本,则可以执行以下操作:

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;
        }
    }
}

现在只需将DOM节点传递给该函数,如下所示:

fixPunctuation(document.body);
fixPunctuation(document.getElementById("foobar"));

答案 3 :(得分:0)

Html不是“常规语言”,因此正则表达式不是解析它的最佳工具。您可能更适合使用html parser like this one to get at the attribute,然后应用正则表达式来对值进行操作。

享受!

答案 4 :(得分:0)

Don't parse regexHTML with HTMLregex。如果您知道HTML格式正确,请使用HTML / XML解析器。否则,首先通过Tidy运行它,然后使用XML解析器。

答案 5 :(得分:0)

如上所述,很多时候,HTML不是常规语言,因此无法使用正则表达式进行解析。

你必须递归地做这件事;我建议抓取DOM对象。

尝试这样的事情......

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"));