You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Java实现:高亮源HTML页面中相似的子HTML内容

解决方案建议

一、先做HTML内容预处理

  • 用Java的HTML解析库(比如jsoup)把源页面和子页面转换成DOM树,分离标签结构与文本内容,避免直接处理原始HTML字符串的杂乱格式。
  • 对提取出的文本做标准化处理:转小写、去除无关标点、分词(英文用OpenNLP,中文用HanLP),同时保留每个单词在源页面DOM中的位置信息(对应节点和文本偏移量),方便后续定位高亮。

二、选择相似度匹配方案

方案1:滑动窗口+编辑距离(简单易实现)

  • 把源页面的单词列表按子页面的单词长度切分成滑动窗口,每个窗口和子页面的单词列表计算Levenshtein编辑距离,设定阈值(比如编辑距离不超过子页面单词数的20%),满足阈值的窗口标记为相似区间。
  • Java中可以自己实现编辑距离算法,或者直接用Apache Commons Lang的StringUtils.getLevenshteinDistance方法快速计算。

方案2:n-gram相似度匹配(适合模糊相似场景)

  • 将文本转换成n-gram(比如2-gram,即连续两个单词的组合),统计子页面的n-gram集合,然后在源页面中扫描连续单词块,找到包含最多子页面n-gram的区间,标记为相似区域。
  • 这种方式能容忍单词顺序小幅度变化,适合内容有局部调整的相似场景。

方案3:图结构实现你的思路(适合复杂变体匹配)

  • 把源页面和子页面的单词作为节点,两个单词的相似度(比如编辑距离小于设定值、或为同义词)作为边的权重,构建二分图。
  • 用最大权重匹配算法(比如KM算法)找到子页面单词到源页面单词的最优匹配,合并匹配上的源页面单词对应的区间,得到相似块。
  • 该方案适合处理有同义词、单词变体的相似场景,但实现复杂度较高,适合需求更精细的场景。

三、在源页面中高亮相似内容

  • 找到相似区间对应的DOM节点后,用jsoup给对应文本片段包裹高亮标签(比如<span style="background-color: yellow;">)。
  • 注意处理跨DOM节点的情况:如果相似内容跨越多个文本节点,需要分别给每个节点内的对应片段添加高亮标签,避免破坏原页面结构。

示例代码片段(jsoup+编辑距离实现)

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.TextNode;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;

public class HtmlSimilarityHighlighter {
    public static void main(String[] args) {
        String sourceHtml = "<div>\nThis is a source page\n</div>";
        String subHtml = "<div>\nThis is blank page\n</div>";

        // 解析HTML并提取单词列表
        Document sourceDoc = Jsoup.parse(sourceHtml);
        Document subDoc = Jsoup.parse(subHtml);
        List<String> sourceWords = extractStandardizedWords(sourceDoc);
        List<String> subWords = extractStandardizedWords(subDoc);

        // 滑动窗口匹配相似区间
        int windowSize = subWords.size();
        double threshold = 0.2;
        List<int[]> matchIntervals = new ArrayList<>();

        for (int i = 0; i <= sourceWords.size() - windowSize; i++) {
            List<String> window = sourceWords.subList(i, i + windowSize);
            int distance = StringUtils.getLevenshteinDistance(
                String.join(" ", window), String.join(" ", subWords)
            );
            if ((double) distance / windowSize <= threshold) {
                matchIntervals.add(new int[]{i, i + windowSize - 1});
            }
        }

        // 高亮匹配文本(简化实现,处理第一个文本节点)
        TextNode textNode = sourceDoc.select("div").first().textNodes().get(0);
        String[] originalWords = textNode.text().split("\\s+");
        StringBuilder highlightedText = new StringBuilder();
        boolean inHighlight = false;

        for (int i = 0; i < originalWords.length; i++) {
            boolean isMatch = matchIntervals.stream().anyMatch(
                interval -> i >= interval[0] && i <= interval[1]
            );
            if (isMatch && !inHighlight) {
                highlightedText.append("<span style='background-color: yellow;'>");
                inHighlight = true;
            } else if (!isMatch && inHighlight) {
                highlightedText.append("</span>");
                inHighlight = false;
            }
            highlightedText.append(originalWords[i]).append(" ");
        }
        if (inHighlight) highlightedText.append("</span>");

        textNode.replaceWith(Jsoup.parse(highlightedText.toString()).child(0));
        System.out.println(sourceDoc.html());
    }

    private static List<String> extractStandardizedWords(Document doc) {
        String cleanText = doc.text().toLowerCase().replaceAll("[^a-zA-Z0-9\\s]", "");
        List<String> words = new ArrayList<>();
        for (String word : cleanText.split("\\s+")) {
            if (!word.isEmpty()) words.add(word);
        }
        return words;
    }
}

注意事项

  • 阈值需根据实际场景调整,比如对相似度要求高则降低阈值,要求低则提高。
  • 处理中文时,替换分词库为HanLP即可,核心逻辑保持一致。
  • 复杂页面需注意DOM节点的遍历顺序,确保每个文本节点都被检查到。

内容的提问来源于stack exchange,提问作者TBKJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 15:17:42