【问题标题】:Regex to search html return, but not actual html jQuery正则表达式搜索 html 返回,但不是实际的 html jQuery
【发布时间】:2011-07-16 22:36:32
【问题描述】:

我正在为客户制作一个突出显示插件以在页面中查找内容,我决定使用帮助查看器进行测试,我 仍在构建,但我遇到了一个问题(可能)需要一些正则表达式。

我不想解析 HTML,我对如何以不同的方式执行此操作完全开放,这似乎是最好/正确的方法。

http://oscargodson.com/labs/help-viewer

http://oscargodson.com/labs/help-viewer/js/jquery.jhighlight.js

在搜索中输入一些内容...好的,刷新页面,现在输入classclass=" 或输入<a 您会注意到它会搜索实际的HTML(如预期的那样)。如何只搜索文本?

如果我这样做.text(),它会蒸发所有 HTML,我得到的只是一大块文本,但我仍然想要 HTML,所以我不会丢失格式、链接、图像等。我想要这就像 CMD/CTRL+F 一样工作。

你会像这样使用这个插件:

$('article').jhighlight({find:'class'});

要删除它们:

.jhighlight('remove')

==UPDATE==

虽然下面 Mike Samuel 的想法确实有效,但对于这个插件来说有点沉重。它主要适用于希望在表单的“发布”过程中删除坏词和/或 MS Word 字符的客户。我正在寻找更轻量级的修复,有什么想法吗?

【问题讨论】:

    标签: javascript jquery search plugins jquery-plugins


    【解决方案1】:

    您真的不想使用 eval、弄乱 innerHTML 或“手动”解析标记。在我看来,最好的方法是直接处理文本节点并保留原始 html 的缓存以擦除高光。使用 cmets 快速重写:

    (function($){
      $.fn.jhighlight = function(opt) {
    
        var options = $.extend($.fn.jhighlight.defaults, opt)
          , txtProp = this[0].textContent ? 'textContent' : 'innerText';
    
        if ($.trim(options.find.length) < 1) return this;
    
        return this.each(function(){
    
          var self = $(this);
    
          // use a cache to clear the highlights
          if (!self.data('htmlCache'))
            self.data('htmlCache', self.html());
    
          if(opt === 'remove'){
            return self.html( self.data('htmlCache') );
          }
    
         // create Tree Walker
         // https://developer.mozilla.org/en/DOM/treeWalker
         var walker = document.createTreeWalker(
              this, // walk only on target element
              NodeFilter.SHOW_TEXT,
              null,
              false
          );
    
          var node
            , matches
            , flags = 'g' + (!options.caseSensitive ? 'i' : '')
            , exp = new RegExp('('+options.find+')', flags) // capturing
            , expSplit = new RegExp(options.find, flags) // no capturing
            , highlights = [];
    
          // walk this wayy
          // and save matched nodes for later
          while(node = walker.nextNode()){
            if (matches = node.nodeValue.match(exp)){
              highlights.push([node, matches]);
            }
          }
    
          // must replace stuff after the walker is finished
          // otherwise replacing a node will halt the walker
          for(var nn=0,hln=highlights.length; nn<hln; nn++){
    
            var node = highlights[nn][0]
              , matches = highlights[nn][1]
              , parts = node.nodeValue.split(expSplit) // split on matches
              , frag = document.createDocumentFragment(); // temporary holder
    
            // add text + highlighted parts in between
            // like a .join() but with elements :)
            for(var i=0,ln=parts.length; i<ln; i++){
    
              // non-highlighted text
              if (parts[i].length)
                frag.appendChild(document.createTextNode(parts[i]));
    
              // highlighted text
              // skip last iteration
              if (i < ln-1){
                var h = document.createElement('span');
                h.className = options.className;
                h[txtProp] = matches[i];
                frag.appendChild(h);
              }
            }
            // replace the original text node
            node.parentNode.replaceChild(frag, node);
          };
    
        });
      };
    
     $.fn.jhighlight.defaults = {
        find:'',
        className:'jhighlight',
        color:'#FFF77B',
        caseSensitive:false,
        wrappingTag:'span'
     };
    
    })(jQuery);
    

    如果您在页面上进行任何操作,您可能希望用另一种清理机制替换缓存,但这并不重要。

    您可以在此处查看代码:http://jsbin.com/anace5/2/

    您还需要在新的 html 元素中添加 display:block,布局在一些浏览器上被破坏。

    【讨论】:

    • 嗯。我不记得为什么我把那个带有捕获组的正则表达式放进去。你可能只保留一个普通的。
    • 哇,这个道具太棒了。你当然应该得到 50 分。现在不要把所有的钱都花在一个地方;)
    • 谢谢。我刚刚注意到一些其他事情:如果元素为空,则 txtProp 测试可能会失败,并且正则表达式搜索有效(即 10 个字符单词:\b\w{10}\b):D
    • 您对这个正则表达式有什么看法:('+settings.find+')(?![^&gt;&lt;]+&gt;) 工作中的某个人提出了建议,我的代码无需更改任何内容即可工作。你能解释一下为什么 eval() 不好吗?你的代码也可以工作,只是寻找最好的和为什么:)
    • 那个正则表达式匹配标签。你不需要关心标签,只关心文本。您当前的代码最终破坏了 HTML,因为它替换了不应该替换的内容。解析 HTML 并非易事,我们有 DOM 可以轻松操作它。
    【解决方案2】:

    在 javascript 代码美化器中,我遇到了这个问题。我想搜索文本但保留标签。

    我所做的是从 HTML 开始,然后将其分解为两个位。

    1. 正文内容
    2. 成对的(索引到出现标签的文本内容,标签内容)

    给定

    Lorem <b>ipsum</b>
    

    我结束了

    text = 'Lorem ipsum'
    tags = [6, '<b>', 10, '</b>']
    

    它允许我搜索文本,然后根据结果开始和结束索引,生成仅包含该范围内的标签(并且仅包含平衡标签)的 HTML。

    【讨论】:

    • 非常感谢。所以,只是想解决这个问题。如果这是实时搜索,我必须为每次击键获取 HTML 和文本?或者,我可以有一个超时功能等待轻微的暂停,但似乎 CPU 密集型,或者您是否建议在页面加载时解析这一切?
    • @Oscar,这个结构可以解析一次并缓存。将其视为搜索索引的一部分。对于您要匹配的模式,您可以在用户键入时构建它,并将其应用于文本。您执行此操作的频率取决于文本的大小,因为将简单的正则表达式与文本字符串匹配的成本是 O(text.length)。
    • 是的,这将是一些 localStorage 的完美用例 :)
    【解决方案3】:

    请看这里:getElementsByTagName() equivalent for textNodes。 您可能可以根据您的需要调整建议的解决方案之一(即迭代所有文本节点,随时替换单词 - 这在&lt;tag&gt;wo&lt;/tag&gt;rd 等情况下不起作用,但我猜总比没有好)。

    【讨论】:

    • 你有我如何实现这个的例子吗?
    • @Oscar,使用对我链接的问题的答复中概述的方法之一迭代所有 TextNode,并在每个 TextNode 上使用 jhighlight()
    【解决方案4】:

    我相信你可以这样做:

    $('#article :not(:has(*))').jhighlight({find : 'class'});
    

    由于它抓取文章中的所有叶节点,因此需要有效的 xhtml,也就是说,它只会匹配以下示例中的 link

    <p>This is some paragraph content with a <a href="#">link</a></p>
    

    DOM 遍历/选择器应用程序可能会减慢速度,所以这样做可能是件好事:

    article_nodes = article_nodes || $('#article :not(:has(*))');
    article_nodes.jhighlight({find : 'class'});
    

    【讨论】:

    • 这似乎打破了正常的发现。将其设为您的选择器,然后键入“example”,仅突出显示“e”,然后完全停止突出显示。 :\ 任何其他想法为什么会这样?
    • 你能检查一下输出是什么:article_nodes.map(function(i,e){ return e.html(); });
    【解决方案5】:

    这样的事情可能会有所帮助

    >+[^<]*?(s(<[\s\S]*?>)?e(<[\s\S]*?>)?e)[^>]*?<+
    

    第一部分&gt;+[^&lt;]*? 查找前面最后一个标签的&gt;

    第三部分[^&gt;]*?&lt;+查找第一个后续标签的&lt;

    在中间我们的搜索词组字符之间有(&lt;[\s\S]*?&gt;)?(在本例中为“see”)。

    正则表达式搜索后,您可以使用中间部分的结果突出显示用户的搜索短语。

    【讨论】:

    • 似乎它可以工作,但我将如何每次构建那个正则表达式?你是说拆分搜索字符串然后循环并构建这个正则表达式然后 eval() 吗?或者,您知道更好的方法吗?
    • 这似乎对我不起作用。例如,当我在“ex”上执行 str.match() 时,我得到:skitch.com/oscargodson/rsdy8/… 这就是我为这个搜索动态创建的正则表达式:(>+[^)?x)([^>]*?skitch.com/oscargodson/rsdy4/help-viewer
    • 奥斯卡,我修改了我的正则表达式。您能否稍微更改脚本 jQuery.jhighlights - 从 eval('/('+settings.find+')/g' 中删除 ()。现在$1 就足够了。
    猜你喜欢
    • 2018-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-01
    • 2012-05-02
    相关资源
    最近更新 更多