gpt4 book ai didi

Javascript 文本高亮功能

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:34:34 25 4
gpt4 key购买 nike

场景

我正在尝试开发一个 Javascript 文本突出显示功能。它在输入中接收要在内部搜索的文本、要搜索的标记数组、包装找到的匹配项的类:

var fmk = fmk || {};

fmk.highlight = function (target, tokens, cls) {
var token, re;
if (tokens.length > 0) {
token = tokens.pop();
re = new RegExp(token, "gi");
return this.highlight(
target.replace(re, function (matched) {
return "<span class=\"" + cls + "\">" + matched + "</span>";
}), tokens, cls);
}
else { return target; }
};

它基于包裹 <span> 的递归替换标记找到的匹配项。

JsFiddle demo .

问题

  1. 如果有两个标记,并且后者是前一个的子字符串那么只有后一个标记会被高亮显示。在 jsFiddle 示例中尝试这些标记:'ab b'。

  2. 如果标记包含包装器序列的子字符串(即 <span class="[className]"></span> )和另一个匹配标记,突出显示失败并返回脏结果。在 jsFiddle 示例中尝试这些标记:'red ab'。

注意在实际应用中允许使用单字符标记。

问题

如何避免这些错误?我想出了这些方法:

  • 预处理标记,移除作为其他标记子串的标记。缺点:需要O(n^2)在 n 个标记的情况下在预处理阶段进行搜索;好的匹配被切断。

  • 在应用包装器之前预处理匹配项,以便仅切断子字符串 匹配项。缺点:同样,需要进一步计算。无论如何,我不知道从哪里开始在替换回调函数中实现它。

最佳答案

我认为处理这个问题的方法是遍历一个元素的所有后代,检查它是否是文本节点,并用 span/class 替换适当的内容。

var MyApp = {};

MyApp.highlighter = (function () {
"use strict";

var checkAndReplace, func,
id = {
container: "container",
tokens: "tokens",
all: "all",
token: "token",
className: "className",
sensitiveSearch: "sensitiveSearch"
};

checkAndReplace = function (node, tokenArr, classNameAll, sensitiveSearchAll) {
var nodeVal = node.nodeValue, parentNode = node.parentNode,
i, j, curToken, myToken, myClassName, mySensitiveSearch,
finalClassName, finalSensitiveSearch,
foundIndex, begin, matched, end,
textNode, span;

for (i = 0, j = tokenArr.length; i < j; i++) {
curToken = tokenArr[i];
myToken = curToken[id.token];
myClassName = curToken[id.className];
mySensitiveSearch = curToken[id.sensitiveSearch];

finalClassName = (classNameAll ? myClassName + " " + classNameAll : myClassName);

finalSensitiveSearch = (typeof sensitiveSearchAll !== "undefined" ? sensitiveSearchAll : mySensitiveSearch);
if (finalSensitiveSearch) {
foundIndex = nodeVal.indexOf(myToken);
} else {
foundIndex = nodeVal.toLowerCase().indexOf(myToken.toLowerCase());
}

if (foundIndex > -1) {
begin = nodeVal.substring(0, foundIndex);
matched = nodeVal.substr(foundIndex, myToken.length);
end = nodeVal.substring(foundIndex + myToken.length, nodeVal.length);

if (begin) {
textNode = document.createTextNode(begin);
parentNode.insertBefore(textNode, node);
}

span = document.createElement("span");
span.className += finalClassName;
span.appendChild(document.createTextNode(matched));
parentNode.insertBefore(span, node);

if (end) {
textNode = document.createTextNode(end);
parentNode.insertBefore(textNode, node);
}

parentNode.removeChild(node);
}
}
};

func = function (options) {
var iterator,
tokens = options[id.tokens],
allClassName = options[id.all][id.className],
allSensitiveSearch = options[id.all][id.sensitiveSearch];

iterator = function (p) {
var children = Array.prototype.slice.call(p.childNodes),
i, cur;

if (children.length) {
for (i = 0; i < children.length; i++) {
cur = children[i];
if (cur.nodeType === 3) {
checkAndReplace(cur, tokens, allClassName, allSensitiveSearch);
} else if (cur.nodeType === 1) {
iterator(cur);
}
}
}
};

iterator(options[id.container]);
};

return func;
})();

window.onload = function () {
var container = document.getElementById("container");
MyApp.highlighter({
container: container,
all: {
className: "highlighter"
},
tokens: [{
token: "sd",
className: "highlight-sd",
sensitiveSearch: false
}, {
token: "SA",
className: "highlight-SA",
sensitiveSearch: true
}]
});
};

演示: http://jsfiddle.net/UWQ6r/1/

我对其进行了设置,以便您可以更改 id 中的值,以便您可以在传递给 highlighter{} 中使用不同的键.

all 对象中的两个设置指的是无论如何都要添加的类,以及区分大小写的搜索覆盖。对于每个标记,您指定标记、类别以及匹配是否区分大小写。

引用资料:

关于Javascript 文本高亮功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16524332/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com