基于栈实现的HTML标签校验器异常问题排查与修复求助
HTML标签校验器问题排查与修复
问题根源
示例1(合法代码误判为异常)
代码将hr标记为自闭合标签,处理<hr>时不会将其压入栈中,但后续遇到</hr>闭合标签时,栈为空,触发"标签不匹配"错误。
示例2(非法代码误判为合法)
同样因为hr被标记为自闭合标签,处理<hr>时不压栈,最终栈为空,被判定为合法,但实际<hr>未闭合,属于非法代码。
修复方案
根据你的需求提供两种修复方式:
方式1:所有标签必须显式闭合
如果要求所有标签(包括hr、br等)都需要手动闭合,只需修改isSelfClosingTag函数,取消自闭合标签的判断:
int isSelfClosingTag(const char* tag) { // 所有标签均需显式闭合,无自闭合标签 return 0; }
修复后效果:
- 输入
<hr></hr>:<hr>压入栈,</hr>匹配弹出,最终栈空,输出Correct! - 输入
<hr>:<hr>压入栈,最终栈不为空,输出Error <hr>
方式2:仅自闭合写法的标签无需闭合
如果遵循HTML标准,仅允许<hr/>这类自闭合写法的标签无需闭合,修改isSelfClosingTag函数,通过标签结尾的/判断自闭合:
int isSelfClosingTag(const char* tag) { int len = strlen(tag); // 检查标签是否以/结尾(自闭合写法) if (len > 0 && tag[len-1] == '/') { // 可选:限制仅指定标签可使用自闭合写法 char* tagName = strdup(tag); tagName[len-1] = '\0'; // 移除末尾的/ static const char* allowedTags[] = {"hr", "br", "img", "input", "meta", "link"}; for (int i = 0; i < sizeof(allowedTags)/sizeof(allowedTags[0]); i++) { if (strcmp(tagName, allowedTags[i]) == 0) { free(tagName); return 1; } } free(tagName); } return 0; }
修复后效果:
- 输入
<hr></hr>:<hr>压入栈,</hr>匹配弹出,输出Correct! - 输入
<hr>:<hr>压入栈,最终栈不为空,输出Error <hr> - 输入
<hr/>:判定为自闭合标签,不压栈,输出Correct!
修复后的完整代码(方式1示例)
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_STACK_SIZE 100 typedef struct { char* items[MAX_STACK_SIZE]; int top; } Stack; void initStack(Stack* s) { s->top = -1; } int isStackEmpty(Stack* s) { return s->top == -1; } int isStackFull(Stack* s) { return s->top == MAX_STACK_SIZE - 1; } void push(Stack* s, const char* item) { if (isStackFull(s)) { fprintf(stderr, "Stack overflow\n"); exit(EXIT_FAILURE); } s->items[++s->top] = strdup(item); } char* pop(Stack* s) { if (isStackEmpty(s)) { return NULL; } return s->items[s->top--]; } char* peek(Stack* s) { if (isStackEmpty(s)) { return NULL; } return s->items[s->top]; } void freeStack(Stack* s) { while (!isStackEmpty(s)) { free(pop(s)); } } int isSelfClosingTag(const char* tag) { // 所有标签均需显式闭合,无自闭合标签 return 0; } void checkHTML(const char* html) { Stack stack; initStack(&stack); const char* p = html; while (*p != '\0') { if (*p == '<') { const char* tagStart = p + 1; const char* tagEnd = strchr(tagStart, '>'); if (tagEnd == NULL) { printf("Error: Invalid tag format\n"); freeStack(&stack); return; } int tagLength = tagEnd - tagStart; char* tag = (char*)malloc(tagLength + 1); strncpy(tag, tagStart, tagLength); tag[tagLength] = '\0'; if (tag[0] == '/') { // 处理闭合标签 if (isStackEmpty(&stack)) { printf("Error <%s>\n", tag); free(tag); freeStack(&stack); return; } char* openTag = pop(&stack); if (strcmp(openTag, tag + 1) != 0) { printf("Error <%s>\n", tag); free(openTag); free(tag); freeStack(&stack); return; } free(openTag); } else { // 处理开启标签 if (!isSelfClosingTag(tag)) { push(&stack, tag); } } free(tag); p = tagEnd; } else { p++; } } // 检查栈中是否有未闭合标签 if (isStackEmpty(&stack)) { printf("Correct!\n"); } else { printf("Error <%s>\n", peek(&stack)); } freeStack(&stack); } int main() { char html[1000]; printf("Enter HTML code (end with an empty line):\n"); fgets(html, sizeof(html), stdin); html[strcspn(html, "\n")] = '\0'; // 移除换行符 checkHTML(html); return 0; }
内容的提问来源于stack exchange,提问作者Nothin Karwy
相关产品推荐
相关产品推荐

