在處理富文本、CMS 內容遷移、XSS 防護等場景時,常需從 HTML 中提取特定標籤的特定屬性並進行替換。本文提供一個通用的 repDomain 方法,結合 Pattern/Matcher 實現「指定標籤 → 指定屬性 → 條件替換」的完整邏輯,並解析正則關鍵點。
public static String repDomain(String source, String domain, String element, String attr) {
// 1. 外層正則:匹配
// [^<>]*? 非貪婪匹配非尖括號字符
// \\s 屬性前必有空白
// (['\"]?) 捕獲引號類型 (單/雙/無)
// (.*?) 非貪婪捕獲屬性值
// \\1 反向引用相同引號
String tagRegex = "<" + element + "[^<>]*?\\s" + attr + "\\s*=\\s*(['\"]?)(.*?)\\1([^<>]*)?>";
Pattern pTag = Pattern.compile(tagRegex, Pattern.CASE_INSENSITIVE);
Matcher mTag = pTag.matcher(source);
StringBuffer result = new StringBuffer();
while (mTag.find()) {
String fullTag = mTag.group(); // 整個標籤
String quote = mTag.group(1); // 引號
String attrValue = mTag.group(2); // 屬性值
String suffix = mTag.group(3); // 剩餘屬性
// 2. 內層條件:只處理包含 "/@tenant" 的值
if (attrValue.contains("/@tenant")) {
int idx = attrValue.indexOf("/@tenant");
String newValue = domain + attrValue.substring(idx + 1); // 替換域名
// 重構標籤
String newTag = fullTag.replace(attrValue, newValue);
mTag.appendReplacement(result, Matcher.quoteReplacement(newTag));
} else {
mTag.appendReplacement(result, Matcher.quoteReplacement(fullTag));
}
}
mTag.appendTail(result);
return result.toString();
}
| 片段 | 含義 |
|---|---|
[^<>]*? | 非貪婪匹配非尖括號,避免跨標籤匹配 |
\\s | 屬性名前必有空白,避免匹配到標籤名一部分 |
(['\"]?) | 捕獲組 1:單引號/雙引號/無引號 (HTML5 允許無引號) |
(.*?) | 捕獲組 2:屬性值,非貪婪 |
\\1 | 反向引用捕獲組 1,確保首尾引號一致 |
([^<>]*)? | 捕獲組 3:該標籤剩餘屬性,供重構時保留 |
String html = "<a href=\"/@tenant/user/123\">Link</a> <img src=\"/static/logo.png\"/>"; String newHtml = repDomain(html, "https://newdomain.com", "a", "href"); // 結果: <a href="https://newdomain.com/user/123">Link</a> <img src="/static/logo.png"/>
>、註解、CDATA、Script/Style 內容等會導致誤匹配。生產環境建議用 Jsoup 或 Jericho 解析器。Document doc = Jsoup.parse(html);
for (Element a : doc.select("a[href]")) {
String href = a.attr("href");
if (href.contains("/@tenant")) a.attr("href", "https://newdomain.com" + href.substring(href.indexOf("/@tenant")+1));
}
return doc.body().html();
Pattern.compile 為重量級操作,靜態常量化複用;大量文本處理考慮 Matcher.replaceAll(Function) (Java 9+)。本文提供的 repDomain 方法展示了「雙層正則 + StringBuffer 重構」的經典替換模式,適用於結構簡單、格式固定的 HTML 片段處理。面對複雜真實 HTML,**務必改用專業解析器 (Jsoup)**,以確保正確性與安全性。