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 解析器。