iOS应用文本搜索高亮问题:阿拉伯语断词与变音符号不敏感需求
Hey,我帮你搞定这两个WebView搜索的问题,还把那个jQuery方案的核心逻辑转成原生JS整合进去了——不用再依赖jQuery啦!
解决iOS WebView文本搜索的阿拉伯语断词与变音符号不敏感问题
你的两个问题其实都和文本处理的细节有关:阿拉伯语的RTL特性+连字依赖上下文,以及变音符号的匹配逻辑。下面是具体的解决方案和整合后的完整代码:
问题1:阿拉伯语单词断开的根源与修复
阿拉伯语是从右到左的语言,字符的形态(比如连字)完全依赖前后文的字符。你原来的代码直接拆分文本节点、插入span的方式会破坏这种上下文关联,导致单词被拆碎。
正确的做法是用**Range API**来选中匹配的文本片段,再用span包裹——这个API会自动处理文本的上下文结构,保留阿拉伯语的原始连字形态,不会出现断词。
问题2:变音符号不敏感搜索的实现
要让不带变音符号的搜索词匹配到带变音符号的内容,我们需要把原文本和搜索词里的所有阿拉伯语变音符号(Tashkeel,Unicode范围是\u064B-\u065F)都移除,再做匹配。我写了一个简单的工具函数来处理这个逻辑。
整合后的完整原生JS代码
下面的代码完全替代你原来的实现,同时解决了两个问题:
var uiWebview_SearchResultCount = 0; // 工具函数:移除阿拉伯语变音符号(Tashkeel) function removeTashkeel(text) { return text.replace(/[\u064B-\u065F]/g, ''); } // 工具函数:用Range包裹匹配文本,避免阿拉伯语断词 function wrapMatchedText(range) { const span = document.createElement("span"); span.className = "uiWebviewHighlight"; span.style.backgroundColor = "#007DC8a3"; span.style.borderRadius = "3px"; span.setAttribute("id", `SEARCH WORD${uiWebview_SearchResultCount}`); // 用Range包裹文本,保留上下文形态 range.surroundContents(span); uiWebview_SearchResultCount++; } /*! * @method uiWebview_HighlightAllOccurencesOfStringForElement * @abstract 递归搜索元素及其子节点,高亮匹配文本 * @param {Element} element - 要搜索的HTML元素 * @param {string} keyword - 预处理后的搜索关键词(已去变音符号+小写) */ function uiWebview_HighlightAllOccurencesOfStringForElement(element, keyword) { if (!element) return; if (element.nodeType === Node.TEXT_NODE) { const originalText = element.nodeValue; const normalizedText = removeTashkeel(originalText).toLowerCase(); let idx = normalizedText.indexOf(keyword); while (idx !== -1) { // 计算匹配文本在原始文本中的准确位置(处理变音符号导致的长度差) let startPos = 0; let tempNormalized = ""; while (tempNormalized.length < idx) { tempNormalized += removeTashkeel(originalText[startPos]); startPos++; } let endPos = startPos; let keywordLength = 0; while (keywordLength < keyword.length) { tempNormalized += removeTashkeel(originalText[endPos]); keywordLength = tempNormalized.slice(idx).length; endPos++; } // 创建Range选中匹配片段 const range = document.createRange(); range.setStart(element, startPos); range.setEnd(element, endPos); // 高亮匹配文本 wrapMatchedText(range); // 更新节点,继续搜索剩余文本 element = range.endContainer; normalizedText = removeTashkeel(element.nodeValue).toLowerCase(); idx = normalizedText.indexOf(keyword); } } else if (element.nodeType === Node.ELEMENT_NODE) { if (element.style.display !== "none" && element.nodeName.toLowerCase() !== 'select') { // 正向遍历子节点,避免DOM修改导致索引混乱 Array.from(element.childNodes).forEach(child => { uiWebview_HighlightAllOccurencesOfStringForElement(child, keyword); }); } } } // 主搜索入口:预处理关键词后开始搜索 function uiWebview_HighlightAllOccurencesOfString(keyword) { uiWebview_RemoveAllHighlights(); // 对搜索关键词做同样的预处理:去变音符号+小写 const normalizedKeyword = removeTashkeel(keyword).toLowerCase(); uiWebview_HighlightAllOccurencesOfStringForElement(document.body, normalizedKeyword); } // 递归移除所有高亮元素 function uiWebview_RemoveAllHighlightsForElement(element) { if (!element) return false; if (element.nodeType === Node.ELEMENT_NODE) { if (element.className === "uiWebviewHighlight") { // 将span内的文本放回原位置,移除span并合并相邻文本节点 const textNode = document.createTextNode(element.textContent); element.parentNode.replaceChild(textNode, element); textNode.parentNode.normalize(); return true; } else { let normalized = false; Array.from(element.childNodes).forEach(child => { if (uiWebview_RemoveAllHighlightsForElement(child)) { normalized = true; } }); if (normalized) element.normalize(); } } return false; } // 移除所有高亮的入口函数 function uiWebview_RemoveAllHighlights() { uiWebview_SearchResultCount = 0; uiWebview_RemoveAllHighlightsForElement(document.body); } // 滚动到指定索引的搜索结果 function uiWebview_ScrollTo(idx) { const targetId = `SEARCH WORD${uiWebview_SearchResultCount - idx}`; const targetElement = document.getElementById(targetId); if (targetElement) { targetElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); } }
关键修改点说明
- 阿拉伯语断词修复:用
Range.surroundContents()替代直接拆分文本节点,完美保留阿拉伯语的连字结构,不会出现单词断开的情况。 - 变音符号不敏感搜索:
removeTashkeel函数统一处理原文本和搜索词的变音符号,确保匹配不受变音符号影响。 - DOM遍历优化:把反向遍历改成正向遍历(
Array.from().forEach),避免因修改DOM导致的子节点索引错乱问题。 - 滚动体验升级:添加了平滑滚动和居中对齐的选项,用户体验更好。
内容的提问来源于stack exchange,提问作者enigrify
相关产品推荐
相关产品推荐

