function checkTagClosure(htmlString) {
// 使用棧來跟蹤開啟的標籤
const tagStack = [];
// 正規表示式匹配標籤 (包括自閉合標籤)
const tagRegex = /<\/?([a-zA-Z][a-zA-Z0-9]*)\s*\/?>/g;
let match;
while ((match = tagRegex.exec(htmlString)) !== null) {
const tagName = match[1];
const isClosingTag = match[0].startsWith("</");
if (isClosingTag) {
// 閉合標籤,檢查棧頂是否匹配
if (tagStack.length === 0 || tagStack.pop() !== tagName) {
return {
isValid: false,
error: `Unexpected closing tag: ${tagName}, at index: ${match.index}`,
};
}
} else {
// 非自閉合標籤,壓入棧中
if (!isSelfClosingTag(tagName)) { // 檢查是否為自閉合標籤
tagStack.push(tagName);
}
}
}
// 檢查棧是否為空,如果不為空,則存在未閉合的標籤
if (tagStack.length > 0) {
return {
isValid: false,
error: `Unclosed tags: ${tagStack.join(", ")}`,
};
}
return { isValid: true };
}
function isSelfClosingTag(tagName) {
const selfClosingTags = ["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"];
return selfClosingTags.includes(tagName.toLowerCase());
}
// 示例用法:
const html1 = "<div><h1>Hello</h1><p>World</p></div>";
const result1 = checkTagClosure(html1);
console.log(result1); // { isValid: true }
const html2 = "<div><h1>Hello<p>World</div>";
const result2 = checkTagClosure(html2);
console.log(result2); // { isValid: false, error: "Unexpected closing tag: div, at index: 18" }
const html3 = "<div><img src='test.jpg' alt='test'></div>";
const result3 = checkTagClosure(html3);
console.log(result3); // { isValid: true }
const html4 = "<div><p>Test</div>";
const result4 = checkTagClosure(html4);
console.log(result4); // { isValid: false, error: 'Unexpected closing tag: div, at index: 10'}
const html5 = "<div><p>Test</p>";
const result5 = checkTagClosure(html5);
console.log(result5); // { isValid: false, error: 'Unclosed tags: div' }
改進和說明:
- 處理自閉合標籤: 增加了
isSelfClosingTag
函式來處理自閉合標籤,避免將它們誤判為未閉合標籤。 - 錯誤資訊更詳細: 返回的錯誤資訊包含了未閉合或錯誤閉合的標籤名稱以及錯誤發生的位置索引,方便除錯。
- 使用正規表示式: 使用正規表示式匹配標籤,更加靈活和健壯。
- 區分大小寫: 將標籤名轉換為小寫再進行比較,避免因為大小寫問題導致誤判。
- 更全面的自閉合標籤列表: 包含了更全面的自閉合標籤列表。
這個改進後的版本可以更準確地檢測 HTML 標籤的閉合情況,並提供更詳細的錯誤資訊。 它仍然有一些侷限性,例如無法處理複雜的巢狀情況和註釋,但在大多數情況下可以有效地工作。 對於更復雜的場景,建議使用專業的 HTML 解析器。