jquery - 使用 jQuery 和 contains() 进行全词匹配
问题描述
我正在编写一个 Greasemonkey 脚本来选择性地隐藏包含讨厌的东西的元素(如果你愿意的话,一个个人网络清洁剂)。
这是我到目前为止所得到的:
//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 是如何工作的。
任何指针将不胜感激!
解决方案
这containsNC
只是这个p:containsCI()
jQuery 扩展的低级版本。
(“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>
笔记:
- Regex like
guns?
允许匹配“gun”和“guns”。 - 由于我们正在构建一个将转换为正则表达式的字符串
\
,因此必须对字符进行转义。那是"\\b"
用来进入\b
正则表达式的。
推荐阅读
- asp.net-mvc - Square API - 在线支付
- html - 椭圆进度条|| 饼形图
- c# - 为什么实体框架不能识别数据库中的现有记录?
- javascript - 我的 recaptcha 渲染不起作用并返回 0
- c# - 在 C# 中处理空值 - 将 Excel 数据表上传到数据库
- html - Flutter:如何在 webview 中显示本地 html 文件?
- video-streaming - 在 HLS 中提供相同音频再现的多种编码
- docker - 无法连接到 Kubernetes 的 ETCD
- arrays - 生成相邻元素不是 x+1 的二维数组
- arrays - 在 for 循环中选择数组的特定行