JavaScript正则表达式 - 匹配和替换匹配中的多个匹配项

时间:2010-08-27 00:03:34

标签: javascript jquery regex

我正在尝试替换某个单词的所有实例,在某些HTML标记之间说“foo”。

<span id=foo> blah blah foo blah foo blah </span>

我想用bar替换不在标签中的所有foo实例,因此最终结果是:

<span id=foo> blah blah bar blah bar blah </span>

请注意,span标记中的“foo”尚未替换。

我可以设法用我的正则表达式替换“foo”的第一个(或最后一个),但不是多个实例。这种情况我应该放弃而不是试图用正则表达式解析它吗?

这是有效的正则表达式:

RegExp('(>[\\w\\s]*)\\bfoo\\b([\\w\\s]*<)',"ig"

或没有javascript语法:

s/>([\w\s]*)\bfoo\b([\w\s]*<)/

此语法允许我匹配(或)匹配

之类的内容

[foo]但不是bar-foo或barfoobar ......任何被替换的foo都需要站在它自己的身上,它不能包含在另一个词中。

作为一个注释,“blah blah”具有不同的长度,可以是许多不同的单词,没有单词或这些的任何组合。

感谢您的任何建议。

7 个答案:

答案 0 :(得分:3)

我不知道以前是否有人提到这一点,但是:

请勿使用REGEX来操作HTML。

这是一个糟糕的工具,无法处理HTML的复杂性。如果你开始替换标记内的字符串,你可以很容易地给自己不仅仅是破坏的标记,而且还有HTML注入漏洞可能导致跨站点脚本漏洞。这样:

(>[\\w\\s]*)

不够,以确保您正在更改的HTML不在标记中。在属性值中包含>字符是完全有效的,更不用说所有其他标记结构。

如果您的语言是在Web浏览器中运行的JavaScript,则没有充分的理由尝试,因为浏览器已经很好地将您的文档解析为Element对象和Text节点。不要让浏览器将所有这些文档对象重新序列化为新的HTML,破解HTML并将其写回innerHTML!除了速度慢之外,这将破坏所有现有内容以用新对象替换它,这会产生丢失所有不可序列化信息的副作用,如表单字段值,JavaScript引用,expandos和事件处理程序。

您可以简单地浏览要查看替换元素的所有Text节点。琐碎的例子:

function replaceText(element, pattern, replacement) {
    for (var childi= element.childNodes.length; childi-->0;) {
        var child= element.childNodes[childi];
        if (child.nodeType==1) # Node.ELEMENT_NODE
            replaceText(child, pattern, replacement);
        else if (child.nodeType==3) # Node.TEXT_NODE
            child.data= child.data.replace(pattern, replacement);
    }
}

replaceText($('#foo')[0], /\bfoo\b/gi, 'bar');

答案 1 :(得分:1)

如果将正则表达式的结果保存为匹配对象,请执行以下操作:

var regex = new RegExp('(>[\\w\\s]*)\\bfoo\\b([\\w\\s]*<)',"ig");
var mystring = "<span id=foo> blah blah foo blah foo blah </span>";
var match = regex.exec(mystring);

您可以使用另一个更简单的正则表达式来再次查看匹配的字符串,以查找多次出现的“foo”。匹配的字符串将位于match[0]

答案 2 :(得分:1)

您好我正在使用jquery进行reg ex替换,以便在我自己的网站上加粗所有p标签的所有首字母。 我认为代码也可以回答您的问题。


<!DOCTYPE html>
<html>
<head>
<title>JQ Replace foo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
#foo {color:#00c;}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('* #foo').each(function(){  //use star to select all elements with id=foo
var me = $(this);
me.html(me.text().replace(/foo/g,"bar"));  // only change text 'foo' to 'bar' , not the html id=foo
});
});
</script> 
</head>
<body>
<div id="foo"> blah blah foo blah foo blah </div>
<p id="foo"> blah blah foo blah foo blah </p>
<a id="foo"> blah blah foo blah foo blah </a>
</body>
</html>

简单但对我有用 John Guise(新西兰)

答案 3 :(得分:0)

以下似乎有效:

var str = "foo yea foot bfoo <span id=foo> blah blah foo blah foo blah </span> foo again <span id=foo>foo again</span>\n\nthis is foo again";
var r = new RegExp("\\bfoo\\b","ig");
str = str.replace(r, "'it works'");
alert(str);

答案 4 :(得分:0)

str = str.replace(/(>[^<]*<)/g, function(s, p1) {
    return p1.replace(/\bfoo\b/g, '');
});

答案 5 :(得分:0)

我很困惑,为什么你不能这样做:

var replacement = $('#foo').html().replace(/\bfoo\b/g, '');
$('#foo').html(replacement);

答案 6 :(得分:0)

我试图以错误的方式做到这一点。这是我创建的解决方案,似乎工作得很好。它使用两个递归函数+ DOM遍历+正则表达式来创建正确的文本和跨节点。

function replaceText(element, pattern, syn_text) {

for (var childi = 0; childi < element.childNodes.length;childi++) {
    var child= element2.childNodes[childi];
    if (child.nodeType==1 && child.className!=syn_text){ //make sure we don't call function on newly created node
        replaceText(child, pattern, syn_text);  //call function on child
    }
    else if (child.nodeType==3){ //this is a text node, being processing with our regular expression
        var str = child.data;
        str = str.replace(pattern,function(s, p1,p2,p3) {
            var parentNode = child.parentNode;
            do_replace(s, p1,p2,p3,parentNode,pattern,syn_text);
            parentNode.removeChild(child);  //delete old child from parent node.  we've replaced it with new nodes at this point
         });
    }
}}




function do_replace(s, p1,p2,p3,parentNode,pattern,syn_text) {
   if(p1.length>0){   //this might not be necessary
     //create textnode
      var text_node = document.createTextNode(p1);
      parentNode.appendChild(text_node);
   }
   if(p2.length > 0){ //create a span + next_node for the highlighting code
      spanTag = document.createElement("span");
      spanTag.id = "SString" + id++;
      spanTag.className = syn_text;
      spanTag.innerHTML = p2;
      parentNode.appendChild(spanTag);
   }
   if(p3.length > 0){
       //test to see if p3 contains another instance of our string.

      if(pattern.test(p3)){  //if there is a instance of our text string in the third part of the string, call function again
          p3.replace(pattern,function(s, p1,p2,p3) {
            //debugger;
            do_replace(s, p1,p2,p3,parentNode,pattern);
            return;
          });
      }
      else{  //otherwise, it's just a plain textnode, so just reinsert it.
          var text_nodep3 = document.createTextNode(p3);
          parentNode.appendChild(text_nodep3);
          return;
      }
    }
    else{ //does this do anything?
        return;
     }
return}

此函数调用如下:

syn_highlight = "highlight_me";  //class to signify highlighting 
pattern = new RegExp('([\\w\\W]*?)\\b('+ searchTerm + '[\\w]*)\\b([\\w\\W]*)',"ig");
replaceText($('#BodyContent')[0],pattern,syn_highlight);