列表

详情


BL11. 实现一个HTML语法检查器

描述

实现一个HTML语法检查器。HTML语法规则简化如下:标签必须闭合,可以由开始和结束两个标签闭合,如<div></div>,也可以自闭合,
如<div />
标签可以嵌套如<div><a></a></div>或者 <div><a/></div>,但是标签不能交叉:<div><a></div></a>是不允许的标签里可以有属性
如<div id="a<1"></div>
属性的规则是name="任意非引号字符",多属性声明之间必须有空格,属性声明不符合规则时,整段HTML都算语法错误
输入文本只会出现字母a-z和<>"=
请用任意语言实现一个HTML语法检查器函数,有语法错误返回1,没有语法错误返回0

输入描述

一行,一个HTML字符串

输出描述

有语法错误返回1,没有语法错误返回0

示例1

输入:

<div><a></a></div>

输出:

0

示例2

输入:

<div><a></div></a>

输出:

1

原站题解

C++ 解法, 执行用时: 2ms, 内存消耗: 488KB, 提交时间: 2020-08-21

#include <iostream>
#include <string>
#include <stack>
  
using namespace std;
  
//判断是否为属性
int isPro(string str, int& i)
{
    if (str[i] >= 'a'&&str[i] <= 'z')
    {
        while (str[i] >= 'a'&&str[i] <= 'z') i++;
        while (str[i] == ' ') i++;
        if (str[i] == '=')
        {
            while (str[++i] == ' ');
            if (str[i] == '\"')
            {
                ++i;
                while (str[i] != '"' && i < str.size()) i++;
                if (str[i] == '"')          //可能是属性
                {
                    if(str[i] == ' ')
                        return 0;
                    else
                    {
                        while (str[i+1] != ' ' && str[i+1] != '<' && str[i+1] != '/' && str[i+1] != '>' && str[i+1] != '\0')
                        {
                            if (str[++i] == '=')
                                return 1;
                        }
                        return 0;
                    }
                }
            }
        }
        else if(str[i] == '/' || str[i] == '>' || str[i] == '<'
            || str[i] == '\0'|| (str[i] >= 'a' && str[i] <= 'z'))
        {
            i--;
            return 0;
        }
    }
    return 1;   //不符合属性格式要求,返回1
}
//判断是否为标签
int isTag(string str, int& i, stack<string>& ss)
{
    if (str[i++] == '<')
    {
        //标签名
        string tagName;
        //判断是否为字母
        if (str[i] >= 'a'&&str[i] <= 'z')   //可能是起始标签
        {
            while (str[i] >= 'a'&&str[i] <= 'z')
            {
                tagName += str[i++];
            } 
            while (str[i] == ' ') i++;      //跳过空格
            if (str[i] >= 'a' && str[i] <= 'z')   //可能是属性
            {
                if (isPro(str, i))              //判断标签内是否带有属性
                {
                    return 1;
                }
                else                            //有属性,跳过全部属性
                {
                    i++;
                    while (str[i] == ' ') i++;
                    while (str[i] >= 'a'&&str[i] <= 'z')
                    {
                        if (isPro(str, i))
                            return 1;
                        while (str[++i] == ' ');
                    }
                }
                if (str[i] == '>')                               //起始标签
                {
                    ss.push(tagName);
                    return 0;
                }
                else if (str[i] == '/' && str[i+1] == '>')       //自闭标签    
                {
                    ++i;
                    return 0;
                }
            }
            else if (str[i] == '/')     //可能是自闭标签
            {
                return (str[++i] == '>') ? 0:1;
            }
            else if (str[i] == '>')      //起始标签
            {
                ss.push(tagName);
                return 0;
            }
        }
        else if (str[i] == '/' && !ss.empty() && ss.top()[0] != '/')                //结束标签
        {
                i++;
                if (str[i] >= 'a'&&str[i] <= 'z')
                {
                    while (str[i] >= 'a'&&str[i] <= 'z')
                    {
                        tagName += str[i++];
                    }
                    //跳过空格
                    while (str[i] == ' ') i++;
                    if (str[i] == '>' && tagName == ss.top())
                    {
                        ss.pop();
                        return 0;
                    }
                }
        }
    }
    //不是标签
    return 1;
}
  
//判断是否符合
int check(string str)
{
    stack<string> ss;
    //判断是否为标签
    for (int i = 0;i < str.size();++i)
    {
        //跳过空格
        while (str[i] == ' ') i++;
        if (str[i] == '<')
        {
            if (isTag(str, i, ss))
                return 1;
        }
        else if ((str[i] >= 'a'&&str[i] <= 'z'))// && !ss.empty())
        {
            if (isPro(str, i))
                return 1;         
        }
        else if (str[i] != '"')
        {
            return 1;
        }
    }
    return ss.empty() ? 0:1;
}
  
int main(int argc, char** argv)
{
    string str;
    getline(cin, str);
    cout << check(str) << endl;
    return 0;
}

C++14 解法, 执行用时: 2ms, 内存消耗: 504KB, 提交时间: 2019-08-21

#include <iostream>
#include <string>
#include <stack>
  
using namespace std;
  
//判断是否为属性
int isPro(string str, int& i)
{
    if (str[i] >= 'a'&&str[i] <= 'z')
    {
        while (str[i] >= 'a'&&str[i] <= 'z') i++;
        while (str[i] == ' ') i++;
        if (str[i] == '=')
        {
            while (str[++i] == ' ');
            if (str[i] == '\"')
            {
                ++i;
                while (str[i] != '"' && i < str.size()) i++;
                if (str[i] == '"')          //可能是属性
                {
                    if(str[i] == ' ')
                        return 0;
                    else
                    {
                        while (str[i+1] != ' ' && str[i+1] != '<' && str[i+1] != '/' && str[i+1] != '>' && str[i+1] != '\0')
                        {
                            if (str[++i] == '=')
                                return 1;
                        }
                        return 0;
                    }
                }
            }
        }
        else if(str[i] == '/' || str[i] == '>' || str[i] == '<'
            || str[i] == '\0'|| (str[i] >= 'a' && str[i] <= 'z'))
        {
            i--;
            return 0;
        }
    }
    return 1;   //不符合属性格式要求,返回1
}
//判断是否为标签
int isTag(string str, int& i, stack<string>& ss)
{
    if (str[i++] == '<')
    {
        //标签名
        string tagName;
        //判断是否为字母
        if (str[i] >= 'a'&&str[i] <= 'z')   //可能是起始标签
        {
            while (str[i] >= 'a'&&str[i] <= 'z')
            {
                tagName += str[i++];
            } 
            while (str[i] == ' ') i++;      //跳过空格
            if (str[i] >= 'a' && str[i] <= 'z')   //可能是属性
            {
                if (isPro(str, i))              //判断标签内是否带有属性
                {
                    return 1;
                }
                else                            //有属性,跳过全部属性
                {
                    i++;
                    while (str[i] == ' ') i++;
                    while (str[i] >= 'a'&&str[i] <= 'z')
                    {
                        if (isPro(str, i))
                            return 1;
                        while (str[++i] == ' ');
                    }
                }
                if (str[i] == '>')                               //起始标签
                {
                    ss.push(tagName);
                    return 0;
                }
                else if (str[i] == '/' && str[i+1] == '>')       //自闭标签    
                {
                    ++i;
                    return 0;
                }
            }
            else if (str[i] == '/')     //可能是自闭标签
            {
                return (str[++i] == '>') ? 0:1;
            }
            else if (str[i] == '>')      //起始标签
            {
                ss.push(tagName);
                return 0;
            }
        }
        else if (str[i] == '/' && !ss.empty() && ss.top()[0] != '/')                //结束标签
        {
                i++;
                if (str[i] >= 'a'&&str[i] <= 'z')
                {
                    while (str[i] >= 'a'&&str[i] <= 'z')
                    {
                        tagName += str[i++];
                    }
                    //跳过空格
                    while (str[i] == ' ') i++;
                    if (str[i] == '>' && tagName == ss.top())
                    {
                        ss.pop();
                        return 0;
                    }
                }
        }
    }
    //不是标签
    return 1;
}
  
//判断是否符合
int check(string str)
{
    stack<string> ss;
    //判断是否为标签
    for (int i = 0;i < str.size();++i)
    {
        //跳过空格
        while (str[i] == ' ') i++;
        if (str[i] == '<')
        {
            if (isTag(str, i, ss))
                return 1;
        }
        else if ((str[i] >= 'a'&&str[i] <= 'z'))// && !ss.empty())
        {
            if (isPro(str, i))
                return 1;         
        }
        else if (str[i] != '"')
        {
            return 1;
        }
    }
    return ss.empty() ? 0:1;
}
  
int main(int argc, char** argv)
{
    string str;
    getline(cin, str);
    cout << check(str) << endl;
    return 0;
}

C++ 解法, 执行用时: 3ms, 内存消耗: 388KB, 提交时间: 2021-03-25

#include<bits/stdc++.h>
using namespace std;

int main(){
    string s;
    getline(cin,s);
    if(s.back()!='>'){
        cout<<1;
        return 0;
    }
    stack<string> st;
    string str="";
    bool flag=false;    //是否需要记录
    bool zibihe=false;
    bool yinhao=false;
    for(int i=0;i<s.length();i++){
       // cout<<i<<" ";
        if(s[i]=='"' && s[i-1]=='='){
            yinhao=true;
        }else if(s[i]=='"' && yinhao){
            yinhao=false;
        }
         if(yinhao){
            continue;
        }
        
         if(s[i]=='<'){
            if(str!=""){
                if(!st.empty() && st.top()==str){
                    st.pop();
                }else {
                    //cout<<str<<endl;
                    st.push(str);
                }
            }
            str="";
            flag=true;
        }else if(s[i]=='/'){
            if(s[i-1]!='<'){
                //<div/>自闭和的情况
                str="";
                flag=false;   
                zibihe=true;
            }
        }else if(s[i]=='>'){
            //cout<<">"<<str<<endl;
            if(!zibihe){                
                //查看栈中的元素是否为str
                if(!st.empty() && st.top()==str){
                    st.pop();
                }else {
                    //cout<<str<<endl;
                    st.push(str);
                }
                str="";
                flag=false;
            }else{
                zibihe=false;
            }
        }else if(s[i]==' '){
            flag=false;
        }else{
            if(flag){
                str.push_back(s[i]);
            }            
        }
    }
    if(st.empty()){
        cout<<0;
    }else{
        cout<<1;
    }
    return 0;
}

C++14 解法, 执行用时: 3ms, 内存消耗: 476KB, 提交时间: 2020-05-20

#include <iostream>
#include <string>
#include <stack>
   
using namespace std;
   
//判断是否为属性
int isPro(string str, int& i)
{
    if (str[i] >= 'a'&&str[i] <= 'z')
    {
        while (str[i] >= 'a'&&str[i] <= 'z') i++;
        while (str[i] == ' ') i++;
        if (str[i] == '=')
        {
            while (str[++i] == ' ');
            if (str[i] == '\"')
            {
                ++i;
                while (str[i] != '"' && i < str.size()) i++;
                if (str[i] == '"')          //可能是属性
                {
                    if(str[i] == ' ')
                        return 0;
                    else
                    {
                        while (str[i+1] != ' ' && str[i+1] != '<' && str[i+1] != '/' && str[i+1] != '>' && str[i+1] != '\0')
                        {
                            if (str[++i] == '=')
                                return 1;
                        }
                        return 0;
                    }
                }
            }
        }
        else if(str[i] == '/' || str[i] == '>' || str[i] == '<'
            || str[i] == '\0'|| (str[i] >= 'a' && str[i] <= 'z'))
        {
            i--;
            return 0;
        }
    }
    return 1;   //不符合属性格式要求,返回1
}
//判断是否为标签
int isTag(string str, int& i, stack<string>& ss)
{
    if (str[i++] == '<')
    {
        //标签名
        string tagName;
        //判断是否为字母
        if (str[i] >= 'a'&&str[i] <= 'z')   //可能是起始标签
        {
            while (str[i] >= 'a'&&str[i] <= 'z')
            {
                tagName += str[i++];
            } 
            while (str[i] == ' ') i++;      //跳过空格
            if (str[i] >= 'a' && str[i] <= 'z')   //可能是属性
            {
                if (isPro(str, i))              //判断标签内是否带有属性
                {
                    return 1;
                }
                else                            //有属性,跳过全部属性
                {
                    i++;
                    while (str[i] == ' ') i++;
                    while (str[i] >= 'a'&&str[i] <= 'z')
                    {
                        if (isPro(str, i))
                            return 1;
                        while (str[++i] == ' ');
                    }
                }
                if (str[i] == '>')                               //起始标签
                {
                    ss.push(tagName);
                    return 0;
                }
                else if (str[i] == '/' && str[i+1] == '>')       //自闭标签    
                {
                    ++i;
                    return 0;
                }
            }
            else if (str[i] == '/')     //可能是自闭标签
            {
                return (str[++i] == '>') ? 0:1;
            }
            else if (str[i] == '>')      //起始标签
            {
                ss.push(tagName);
                return 0;
            }
        }
        else if (str[i] == '/' && !ss.empty() && ss.top()[0] != '/')                //结束标签
        {
                i++;
                if (str[i] >= 'a'&&str[i] <= 'z')
                {
                    while (str[i] >= 'a'&&str[i] <= 'z')
                    {
                        tagName += str[i++];
                    }
                    //跳过空格
                    while (str[i] == ' ') i++;
                    if (str[i] == '>' && tagName == ss.top())
                    {
                        ss.pop();
                        return 0;
                    }
                }
        }
    }
    //不是标签
    return 1;
}
   
//判断是否符合
int check(string str)
{
    stack<string> ss;
    //判断是否为标签
    for (int i = 0;i < str.size();++i)
    {
        //跳过空格
        while (str[i] == ' ') i++;
        if (str[i] == '<')
        {
            if (isTag(str, i, ss))
                return 1;
        }
        else if ((str[i] >= 'a'&&str[i] <= 'z'))// && !ss.empty())
        {
            if (isPro(str, i))
                return 1;         
        }
        else if (str[i] != '"')
        {
            return 1;
        }
    }
    return ss.empty() ? 0:1;
}
   
int main(int argc, char** argv)
{
    string str;
    getline(cin, str);
    cout << check(str) << endl;
    return 0;
}

C++ 解法, 执行用时: 3ms, 内存消耗: 480KB, 提交时间: 2019-08-15

#include <iostream>
#include <string>
#include <stack>

using namespace std;

//判断是否为属性
int isPro(string str, int& i)
{
	if (str[i] >= 'a'&&str[i] <= 'z')
	{
		while (str[i] >= 'a'&&str[i] <= 'z') i++;
		while (str[i] == ' ') i++;
		if (str[i] == '=')
		{
			while (str[++i] == ' ');
			if (str[i] == '\"')
			{
				++i;
				while (str[i] != '"' && i < str.size()) i++;
				if (str[i] == '"')			//可能是属性
				{
					if(str[i] == ' ')
						return 0;
					else
					{
						while (str[i+1] != ' ' && str[i+1] != '<' && str[i+1] != '/' && str[i+1] != '>' && str[i+1] != '\0')
						{
							if (str[++i] == '=')
								return 1;
						}
						return 0;
					}
				}
			}
		}
		else if(str[i] == '/' || str[i] == '>' || str[i] == '<' 
			|| str[i] == '\0'|| (str[i] >= 'a' && str[i] <= 'z'))
		{
			i--;
			return 0;
		}
	}
	return 1;	//不符合属性格式要求,返回1
}
//判断是否为标签
int isTag(string str, int& i, stack<string>& ss)
{
	if (str[i++] == '<')
	{
		//标签名
		string tagName;
		//判断是否为字母
		if (str[i] >= 'a'&&str[i] <= 'z')   //可能是起始标签
		{
			while (str[i] >= 'a'&&str[i] <= 'z')
			{
				tagName += str[i++];
			}	
			while (str[i] == ' ') i++;		//跳过空格
			if (str[i] >= 'a' && str[i] <= 'z')	//可能是属性
			{
				if (isPro(str, i))				//判断标签内是否带有属性
				{
					return 1;
				}
				else							//有属性,跳过全部属性
				{
					i++;
					while (str[i] == ' ') i++;
					while (str[i] >= 'a'&&str[i] <= 'z')
					{
						if (isPro(str, i))
							return 1;
						while (str[++i] == ' ');
					}
				}
				if (str[i] == '>')					            //起始标签
				{
					ss.push(tagName);
					return 0;
				}
				else if (str[i] == '/' && str[i+1] == '>')		//自闭标签		
				{
					++i;
                    return 0;
				}
			}
			else if (str[i] == '/')		//可能是自闭标签
			{
                return (str[++i] == '>') ? 0:1;
			}
			else if (str[i] == '>')		//起始标签
			{
				ss.push(tagName);
				return 0;
			}
		}
		else if (str[i] == '/' && !ss.empty() && ss.top()[0] != '/')				//结束标签
		{
				i++;
				if (str[i] >= 'a'&&str[i] <= 'z')
				{
					while (str[i] >= 'a'&&str[i] <= 'z')
					{
						tagName += str[i++];
					}
					//跳过空格
					while (str[i] == ' ') i++;
					if (str[i] == '>' && tagName == ss.top())
					{
						ss.pop();
						return 0;
					}
				}
		}
	}
	//不是标签
	return 1;
}

//判断是否符合
int check(string str)
{
	stack<string> ss;
	//判断是否为标签
	for (int i = 0;i < str.size();++i)
	{
		//跳过空格
		while (str[i] == ' ') i++;
		if (str[i] == '<')
		{
			if (isTag(str, i, ss))
				return 1;
		}
		else if ((str[i] >= 'a'&&str[i] <= 'z'))// && !ss.empty())
		{
			if (isPro(str, i))
				return 1;			
		}
		else if (str[i] != '"')
		{
			return 1;
		}
	}
	return ss.empty() ? 0:1;
}

int main(int argc, char** argv)
{
	string str;
	getline(cin, str);
	cout << check(str) << endl;
	return 0;
}

上一题