用户将提供一些搜索字词。我们只是说它是一个字符串,可能包含任何单词或特殊字符(如/
,?
,,
,$
,*
等。
我需要将这些字符序列与HTML中出现的任何字符进行匹配,即使搜索字词跨越连续跨度;在我的HTML中,特殊字符有时会单独包装。
例如:用户提供“你的妈妈?”,并且有一段包含<span>Your mom</span><span class="special">?</span>
我需要一种有效的方法来确定a)查询是否存在,以及b)哪些元素包含查询。搜索到的文本可以是复杂的HTML,包含很多单词,跨度,div等等。
答案 0 :(得分:2)
我可能会尝试编写一个解析器来区分标签的打开和关闭,以及它们的文本内容(希望HTML不包含不完整的标签)。对于索引,也许你可以使用一堆元组,每个元组代表深度和计数,以及当前状态的内存。您的简单示例将索引为:
[(1,1)] tag opens, text: 'Your mom'
query text matches so far
[(1,1),(1,1)] tag closes, remove.
[(1,2)] tag opens, maintain depth, increase count, text: '?'
query text continues to match
[(1,2)] tag closes, remove
答案 1 :(得分:1)
首先,您必须将“字符”拆分为多个组。最偏执的方式是按性格,但最终效率会非常低。知道我对你的数据做了什么,我认为任何匹配[a-zA-Z\s]+
的东西都会成为一个令牌而其他一切都变成另一个令牌。
可能合乎逻辑的另一件事是做一个迭代过程,在每次失败的尝试之后,你将其进一步分解。
无论你决定什么,你都需要使用一些JavaScript来做到这一点。但这应该相当容易。
在拆分之后,你需要开始考虑构建一个正则表达式。
您可以在每个令牌之间放置(?:<[^>]*>\s*)*
,但在将它们放入正则表达式之前,某些字符需要进行转义。某处有一个完整的列表,但其中包括:$^*.+?/\{}[]()
。
对于您的示例,您最终可能会得到以下内容:
/your mom(?:<[^>]*>\s*)*\?/i
i
表示不区分大小写。
您可以获取匹配位置的索引,例如this:
var match = /regex/.exec("string to match against");
if (match) {
alert("match found at " + match.index);
}
答案 2 :(得分:1)
此解决方案将查找并返回包含搜索文本的第一个元素,即使该文本包含嵌入的标记。
TL; DR 播放示例!
var content = $("#content");
var search = $("#search");
var go = $("#go");
function escapeRegExp(str) {
return str.replace(/[\/\\{}()*+?.^$|[\]-]/g, "\\$&");
}
function recursiveElementSearch(regex, element) {
var text = element.text();
if (text.match(regex)) {
var children = element.children();
var len = children.length;
for (var i=0; i < len; ++i) {
var child = $(children[i]);
var found = recursiveElementSearch(regex, child);
if (found != null) {
return found;
}
}
return element;
}
return null;
}
go.click(function() {
var value = $.map(search.val().split(""), function(value, index) {
return escapeRegExp(value);
});
var regex = new RegExp(value.join(""), "i");
var element = recursiveElementSearch(regex, content);
console.log("Element: ", element ? element.attr("id") : "null");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="content">
<div id="first">
<span id="a">Your mom</span><span class="special">?</span>
</div>
<div id="second">
<span id="b">Where is <strong>your</strong> mom</span><span class="special">?</span>
</div>
<div id="third">
<span id="c">Yours<span> </span><a href="#">mom</a></span><span class="special">?</span>
</div>
<div id="fourth">
<span id="d">My mom</span><span class="special">!</span>
</div>
<div id="fifth">
<span id="e">Their mom<i>s</i></span><span class="special">...</span>
</div>
</div>
<input id="search" value="Your mom?">
<label for="search">Search:</label>
<button id="go">Go!</button>
这种方法的工作方式是对输入文本进行清理(转义),然后递归检查每个元素的文本以查看是否包含搜索文本。
将返回的元素是在最深层找到的第一个元素。搜索是深度优先的,因此在第一个元素上找到3个深度的匹配将在第二个元素的深度为1级之前返回。
提供的HTML代码段显示嵌套代码不是问题。使用此HTML,“你的妈妈?”的搜索结果返回div id="first"
,搜索“妈妈!”返回div id="fourth"
,搜索“你的妈妈”会返回div id="c"
。
可以进行一些简单的改进。以下是我在测试中看到的有用信息:
div id="first"
,div id="second"
],因为两者都匹配)鉴于所有这些,这是一种非常有用的搜索页面文本的方法。