首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 處理巢狀 HTML 標籤:用堆疊匹配取代正則的實戰方案

     編輯:Java 相關知識

問題背景

Java 內建正則引擎不支援遞迴/巢狀結構描述(Perl、.NET、PHP 支援)。若需從 HTML 字串提取巢狀標籤內容(如 <div>...</div> 內含另一組 <div>),直接用正則會失敗或誤匹配。

解決思路:位置記錄 + 堆疊匹配

  1. 用正則找出所有起始/結束標籤在字串中的 位置
  2. 遍歷標籤列表,起始標籤入堆疊,結束標籤出堆疊匹配
  3. 堆疊為空時,表示找到最外層完整巢狀區塊,截取內容

核心資料結構:Tag 類別

public class Tag {
    private String value;      // 標籤字串,如 "
" private int beginPos; // 起始索引 private int endPos; // 結束索引 public Tag(String value, int beginPos, int endPos) { this.value = value; this.beginPos = beginPos; this.endPos = endPos; } // getter/setter 略 }

核心演算法:get 方法

public List get(String data, String stag, String etag) {
    Stack work = new Stack<>();           // 匹配用堆疊
    List allTags = new ArrayList<>();     // 所有標籤位置記錄

    // 1. 轉義正則元字元
    String nstag = stag.replaceAll("([\\*\\.\\+\\(\\)\\[\\]\\?\\{\\}\\^\\$\\|\\\\])", "\\\\$1");
    String netag = etag.replaceAll("([\\*\\.\\+\\(\\)\\[\\]\\?\\{\\}\\^\\$\\|\\\\])", "\\\\$1");
    String reg = "((?:" + nstag + ")|(?:" + netag + "))";

    // 2. 找出所有標籤位置
    Pattern p = Pattern.compile(reg, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
    Matcher m = p.matcher(data);
    while (m.find()) {
        allTags.add(new Tag(m.group(0), m.start(), m.end()));
    }

    // 3. 堆疊匹配提取內容
    List result = new ArrayList<>();
    for (Tag t : allTags) {
        if (stag.equalsIgnoreCase(t.getValue())) {
            work.push(t);                       // 起始標籤入堆疊
        } else if (etag.equalsIgnoreCase(t.getValue())) {
            if (work.empty()) throw new RuntimeException("pos " + t.getBeginPos() + " tag not match start tag.");
            Tag otag = work.pop();              // 配對起始標籤
            if (work.empty()) {                 // 堆疊空 → 最外層匹配完成
                result.add(data.substring(otag.getEndPos(), t.getBeginPos()));
            }
        }
    }
    if (!work.empty()) throw new RuntimeException("tag " + work.pop().getValue() + " not match.");
    return result;
}

實戰測試

String data = "
abcd
1234
"; List res = get(data, "
", "
"); // 返回兩個元素: // 1. "
abcd
" // 2. "1234"

關鍵細節

  • 元字元轉義:第 16-17 行自動為標籤字串中的正則特殊字元加反斜線,避免編譯錯誤
  • 大小寫不敏感:Pattern.CASE_INSENSITIVE 適應 HTML 大小寫不一
  • 錯誤檢測:堆疊最終非空或提前空,均拋出異常提示位置

適用場景

HTML/XML 片段解析、模板引擎標籤提取、程式碼區塊分析等所有「巢狀成對標記」場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved