使用jQuery和contains()进行全字匹配

时间:2018-11-12 12:51:51

标签: jquery jquery-selectors userscripts tampermonkey greasemonkey-4

我正在编写一个Greasemonkey脚本,以有选择地隐藏包含令人讨厌的东西的元素(如果需要,可以使用个人Web消毒剂)。

这是到目前为止我得到的:

//custom contains function which is case-insensitive
$.extend($.expr[":"], {
  "containsNC": function(elem, i, match, array) {
    return (elem.textContent || elem.innerText || "").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
  }
});

//build array of words to filter
var nope = "long list of horrible words".toLowerCase().split(' ');

//start with an empty jQuery object
var nopeEles = $();

//add elements to filter to it
for (var i = 0; i < nope.length; i++) {
  nopeEles = nopeEles.add( $("a:containsNC('" + nope[i] + "')") );
  nopeEles = nopeEles.add( $("p:containsNC('" + nope[i] + "')") );
}

//hide all applicable elements
nopeEles.css("background-color", "white");
nopeEles.css("color", "white");

它工作得不错,但是却进行了部分单词匹配,这使得短单词不起作用。我想过滤包含“ die”和“ gun”等词的元素,而不过滤包含“ candied”或“ gung-ho”等词的元素。

需要明确的是,我追求的是全字词,而不是确切的文字。我希望列表中的“枪”不仅要匹配“枪”,还要匹配“他开枪”和“开枪”。而不是“甘尼中士”。

我在该主题上看到的所有其他答案都建议使用jQuery的filter()。我想我不太了解。我尝试在循环中使用此行,但没有执行任何操作:

nopeEles = nopeEles.add( $("a").filter(function() { return $(this).text() === nope[i]; }) );

我想看的另一个角度是摆弄containsNC,所以它寻找单词,但两侧都带有空格或字符串结尾。不过,我不太了解containsNC的工作原理。

任何指针将不胜感激!

1 个答案:

答案 0 :(得分:2)

containsNC只是this p:containsCI() jQuery extension的一个低于标准版本。
(“ NC” ==“没有大小写”≈≈“ CI” ==“不区分大小写”。)

改为使用链接的jQuery扩展,然后您可以使用正则表达式来匹配整个单词,例如:

nopeEles = nopeEles.add( $("a:containsCI('\\b" + nope[i] + "\\b')") );

但是,该问题代码效率很低,您会发现它会使页面变慢,因为它将整个页面扫描2N次(其中N是项数)乘以J子字符串扫描(其中J是<a><p>节点)。

一种更高效的方法是通过合并正则表达式只扫描每个节点一次。观看此演示:

jQuery.extend (
    jQuery.expr[':'].containsCI = function (a, i, m) {
        var sText   = (a.textContent || a.innerText || "");
        var zRegExp = new RegExp (m[3], 'i');
        return zRegExp.test (sText);
    }
);

//-- Build array of terms to filter:
var badTerms    = ['die', 'guns?', 'agitators?'];
//-- Build ONE regex string for speed and efficiency:
var cnsrRegEx   = `\\b(${badTerms.join ("|")})\\b`;  //  \b is word-break regex.

var nopeEles    = $("a, p").filter (":containsCI('" + cnsrRegEx + "')");

//-- Hide all applicable elements:
nopeEles.css ( {
    "background-color": "white",
    "color": "white"
} );
a, p {border: 1px solid lightgray; padding: 0.3ex 1ex;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<p>All good</p>
<p>All bad agitators</p>
<div>Some bad: <a>die</a> <a>gun</a> <a>candied</a> <a>gung-ho</a> <a>guns</a>
  <a>he fired a gun</a> <a>gunney sergeant</a>
</div>

注意:

  1. guns?这样的正则表达式允许同时匹配“ gun”和“ guns”。
  2. 由于我们正在构建要转换为正则表达式的 string ,因此必须转义\个字符。即使用"\\b"在正则表达式中获取\b