Регулярные выражения JavaScript - сопоставление и замена нескольких совпадений внутри совпадения - PullRequest
1 голос
/ 27 августа 2010

Я пытаюсь заменить все вхождения слова, скажем "foo", между некоторыми тегами HTML.

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

Я хочу заменить все экземпляры foo, отсутствующие в теге, на bar, поэтому конечный результат:

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

Обратите внимание, что "foo" в теге span не был заменен.

Мне удается заменить первое (или последнее) вхождение слова "foo" на мое регулярное выражение, но не на несколько экземпляров. Это ситуация, когда я должен сдаться, а не пытаться анализировать это с помощью регулярного выражения?

Вот регулярное выражение такого рода работ:

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

или без синтаксиса JavaScript:

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

этот синтаксис позволяет мне сопоставлять (или должен ) совпадать с такими вещами, как

[foo], но не bar-foo или barfoobar ... любое вхождение заменяемого foo должно стоять само по себе, оно не может содержаться в другом слове.

Как примечание, «бла-бла» имеет различную длину и может состоять из множества разных слов, без слов или любой их комбинации.

Спасибо за любые предложения.

Ответы [ 7 ]

3 голосов
/ 27 августа 2010

Я не знаю, упоминал ли кто-нибудь об этом раньше, но:

НЕ ИСПОЛЬЗУЙТЕ РЕЕКС для манипулирования HTML.

Это плохой инструмент, который далеко не готов к работе со сложностью HTML. Если вы начнете заменять строки внутри разметки, вы можете легко получить не только разбитую разметку, но и дыры в HTML-инъекциях, потенциально приводящие к уязвимостям межсайтового скриптинга. Это:

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

недостаточно , чтобы убедиться, что изменяемый вами HTML не находится в разметке. Вполне допустимо иметь символ > в значении атрибута, не говоря уже о всех других конструкциях разметки.

Если ваш язык - JavaScript, работающий в веб-браузере, нет веских причин даже пытаться это сделать, потому что браузер уже хорошо проанализировал ваш документ на объекте Element и текстовых узлах. Не просите браузер повторно сериализовать все эти объекты документа в новый HTML, взломайте HTML и запишите его обратно в innerHTML! Помимо медленной работы, это приведет к разрушению всего существующего контента и замене его новыми объектами, что побочным эффектом приведет к потере всей несериализуемой информации, такой как значения полей формы, ссылки JavaScript, расширения и обработчики событий.

Вы можете просто пройтись по всем узлам 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 голос
/ 02 декабря 2010

Привет, я делал reg ex replace на jquery, чтобы выделить все первые слова всех тегов 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>

Просто, но у меня работает Джон Гиз (Новая Зеландия)

1 голос
/ 27 августа 2010

Если вы сохраните результаты из своего регулярного выражения в виде объекта сопоставления, например, так:

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].

0 голосов
/ 30 августа 2010

Я пытался сделать это неправильно.Вот решение, которое я создал, и, кажется, отлично работает.Он использует две рекурсивные функции + обход 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);
0 голосов
/ 27 августа 2010

Я в замешательстве, почему ты не можешь сделать:

var replacement = $('#foo').html().replace(/\bfoo\b/g, '');
$('#foo').html(replacement);
0 голосов
/ 27 августа 2010
str = str.replace(/(>[^<]*<)/g, function(s, p1) {
    return p1.replace(/\bfoo\b/g, '');
});
0 голосов
/ 27 августа 2010

Кажется, работает следующее:

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...