JavaScript正则表达式匹配文本忽略HTML。

10

在 "The <strong>dog</strong> is really <em>really</em> fat!" 中匹配 "the dog is really really fat",并在其周围添加 "<span class="highlight">WHAT WAS MATCHED</span>",是否可能?

我的意思不是具体指这个例子,而是一般情况下能够忽略HTML搜索文本,将其保留在最终结果中,只需在其上方添加 span,是否可能?

编辑:
考虑到 HTML 标签重叠问题,是否可以匹配一个短语,并仅在每个匹配的单词周围添加 span?问题在于当单词“dog”不在搜索上下文中时,我不希望它被匹配,例如“the dog is really really fat。”


1
一般来说不要使用正则表达式来处理HTML,应该使用HTML解析器。同时,请在StackOverflow中使用代码高亮功能。 - g.d.d.c
5
他并不是这样的,他只是想匹配特定的文本。 - b01
除了 JavaScript,我没有其他可以接触的东西。我本以为使用了反引号,结果却使用了引号。 - Francisc
这还不算糟糕。那么,<strong>我说这只</strong>狗真的很胖!你觉得呢? 你打算让它看起来像这样吗:<strong>我说<span class="highlight">这只</strong>狗真的很胖!</span>你觉得呢? - BishopRook
考虑将该类添加到每个匹配的单词中。 - Francisc
显示剩余3条评论
7个回答

9

更新:

这里有一个可以实现您想要的功能的有效示例。然而,您需要更新htmlTagRegEx来处理匹配任何HTML标记,因为它只执行简单匹配,无法处理所有情况。

http://jsfiddle.net/briguy37/JyL4J/

此外,下面是代码。基本上,它逐个删除HTML元素,然后在文本中进行替换以添加匹配选择周围的突出显示span,最后逐个推回HTML元素。它很丑陋,但这是我能想到的最简单的方法来让它工作...

function highlightInElement(elementId, text){
    var elementHtml = document.getElementById(elementId).innerHTML;
    var tags = [];
    var tagLocations= [];
    var htmlTagRegEx = /<{1}\/{0,1}\w+>{1}/;

    //Strip the tags from the elementHtml and keep track of them
    var htmlTag;
    while(htmlTag = elementHtml.match(htmlTagRegEx)){
        tagLocations[tagLocations.length] = elementHtml.search(htmlTagRegEx);
        tags[tags.length] = htmlTag;
        elementHtml = elementHtml.replace(htmlTag, '');
    }

    //Search for the text in the stripped html
    var textLocation = elementHtml.search(text);
    if(textLocation){
        //Add the highlight
        var highlightHTMLStart = '<span class="highlight">';
        var highlightHTMLEnd = '</span>';
        elementHtml = elementHtml.replace(text, highlightHTMLStart + text + highlightHTMLEnd);

        //plug back in the HTML tags
        var textEndLocation = textLocation + text.length;
        for(i=tagLocations.length-1; i>=0; i--){
            var location = tagLocations[i];
            if(location > textEndLocation){
                location += highlightHTMLStart.length + highlightHTMLEnd.length;
            } else if(location > textLocation){
                location += highlightHTMLStart.length;
            }
            elementHtml = elementHtml.substring(0,location) + tags[i] + elementHtml.substring(location);
        }
    }

    //Update the innerHTML of the element
    document.getElementById(elementId).innerHTML = elementHtml;
}

谢谢,但我需要匹配文本并仍保留标签。 - Francisc
@Francisc:对文本进行匹配。如果匹配成功,则获取带有innerHTML的HTML。 - Briguy37
是的,但是 innerHTML 的内容是什么?文本可能是:<p>The dog is <i>really really</i> fat.</p>,我想找到 dog is really 并在其周围添加 <span>,但这会重叠 <i> 元素。 - Francisc
哇,那肯定花了很长时间才写出来。非常感谢你。 - Francisc
请注意,用户可能会搜索“strong”,而HTML将弹出...这不是最好的用户体验。 - posixpascal
显示剩余3条评论

4
使用JQuery更简单的方法如下:
originalHtml = $("#div").html();

    newHtml = originalHtml.replace(new RegExp(keyword + "(?![^<>]*>)", "g"), function(e){
                      return "<span class='highlight'>" + e + "</span>";
                   });

$("#div").html(newHtml);

这对我来说完全没问题。

4

不需要那么麻烦,只需使用老牌的 RegExp;)

var htmlString = "The <strong>dog</strong> is really <em>really</em> fat!";
var regexp = /<\/?\w+((\s+\w+(\s*=\s*(?:\".*?"|'.*?'|[^'\">\s]+))?)+\s*|\s*)\/?>/gi;
var result = '<span class="highlight">' + htmlString.replace(regexp, '') + '</span>';

1
看起来很好啊...现在是圣诞节了吗?不管怎样,我认为那并不能解决HTML标签重叠的问题,对吧? - Francisc
您在哪里输入搜索词语? :) - Francisc
抱歉,我错过了最后一个。正则表达式将匹配每个HTML标记。 - Ivan Nikolchov
哦,我想我明白了,它会剥离所有的HTML标签,对吗? - Francisc
啊,是的,我需要的是让它与人类阅读的文本匹配,并添加高亮类。 :) - Francisc

1
this.keywords.forEach(keyword => {
  el.innerHTML = el.innerHTML.replace(
    RegExp(keyword + '(?![^<>]*>)', 'ig'),
    matched => `<span class=highlight>${matched}</span>`
  )
})

1

这里有一个有效的正则表达式示例,可以排除HTML标签和JavaScript中的匹配项:

在replace()脚本中使用此正则表达式。

/(a)(?!([^<])*?>)(?!<script[^>]*?>)(?![^<]*?<\/script>|$)/gi

0
你可以使用字符串替换表达式</?\w*>来获取你的字符串。

-2
如果您使用jQuery,可以在包含要搜索的文本的元素上使用text属性。给定此标记:
<p id="the-text">
  The <strong>dog</strong> is really <em>really</em> fat!
</p>

这会得到 "狗真的真的很胖!":
$('#the-text').text();

你可以在文本中进行正则表达式搜索,而不是尝试在标记中进行搜索。

如果没有jQuery,我不确定是否有一种简单的方法来提取和连接所有子元素的文本节点。


我认为我不能使用jQuery。 - Francisc
哦,是的,我忘记了jQuery文本。为什么你不能使用jQuery呢? - b01

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接