元素选择器

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
解题思路

  • 本题将输入的每行字符串转换成特定的标签、id,进行相应操作即可
  • 用结构体储存每个行,包括层级、父节点的行号、标签、id;用结构体数组存储所以行。
  • 每次输入一行,用getline将其读入一个字符串,通过点的个数得到层级数,之后从当前数组中最后一个元素开始往上找它的父节点,即level比它小1的;之后通过判断#是否存在来判断之后读入数据的类型,如果是标签则全部转换为小写(因为大小写不敏感);得到了当前行的结构体的四个元素的值,将其插入数组。
  • 每次输入选择器,用getline读入,通过空格看是否有多级(找空格的位置),如果没有空格则是前两种单一选择器,通过首位是否为#判断类型。遍历搜索,输出对应行数即可。
  • 如果是多级选择器(空格找到),用空格作为分解符,每次通过每个段的首元素是否为‘#’判断类型,把每个段存储到数组中,倒序查找,每找到一个后循环把前一个和他的父节点比较,都相同则记录。最后输出即可。

完整代码

#include <iostream>
#include <vector>
using namespace std;
#include <cctype>
struct html
{
	int level;//层级
	int father;//父结点行号
	string label;
	string id;
};

vector<html> doc;//文档向量
vector<int> num;//结果向量
int main(){
	int n,m,fa,le;
	cin>>n>>m;
	getchar();
	while(n--)
	{//处理文档
		string s,la,id;
		getline(cin,s);
		int lee = 0;
		while(s[lee] == '.')	
			lee++;
		le = lee / 2;//得到层级数 
		if(lee == 0 || !doc.size())	
			fa = -1	;
		else{
			for(int i = doc.size() - 1;i >= 0;i--){
				if(doc[i].level == le - 1)//从最后一个元素开始往上找它的父节点,即level小1的 
				{
					fa = i;
					break;
				}
			}
		}
		bool flag = false;//表示是否有属性 
		while(lee < s.size())//忽略空格 
		{
			if(s[lee] == ' ')
			{
				lee++;
				continue;
			}
			if(s[lee] == '#')
			{
				flag = true;//有属性 
				id += s[lee];
				lee++;
				continue;
			}
			if(flag)	id += s[lee];
			else	la += tolower(s[lee]);//全部转换为小写,大小写不敏感 
			lee++;
		}
		doc.push_back({le,fa,la,id});
	}
	
	while(m--){//选择
		string s;
		getline(cin,s);
		int p = 0;
		while(p != s.size() - 1 && s[p] != ' ')	//通过空格看是否有二重 
			p++;
		if(p == s.size() - 1)
		{//单一选择器
			if(s[0] == '#')//id选择器 
			{
				for(int i = 0;i < doc.size();i++){
					if(s == doc[i].id)	num.push_back(i+1);	
				}	
			}
			else//标签选择器 
			{
				for(int i = 0;i < s.size();i++)	s[i] = tolower(s[i]);				
				for(int i = 0;i < doc.size();i++){
					if(s == doc[i].label)	num.push_back(i+1);	
				}
			}
			cout<<num.size()<<" ";
			for(int i = 0;i < num.size();i++)	cout<<num[i]<<" ";
		}
		else//二重 
		{
			int j = 0;
			vector<string> v;
			p = 0;
			bool flag = true;
			while(p < s.size()){
			if(s[p] == '#')	flag = false;
			if(s[p] == ' ')//第二个 
			{
				flag = true;//还原标志变量
				v.push_back(s.substr(j,p-j));//各个层插入 
				j = p + 1;
			}
			if(flag)//id选择器,不区分大小写 
				s[p] = tolower(s[p]);//转为小写 
			p++;
			}
			v.push_back(s.substr(j,p-j));
			for(int i = doc.size() - 1;i > 0;i--)//遍历 
			{
				int q = v.size() - 1;
				if(v[q] != doc[i].label && v[q] != doc[i].id)//啥也不是 
					continue;
				p = doc[i].father,q--;
				while(q >= 0 && p >= 0){
					if(doc[p].label == v[q] || doc[p].id == v[q])	q--;		
					p = doc[p].father;
				}
				if(q == -1)	num.push_back(i+1);
			}
			cout<<num.size()<<" ";
			for(int i = num.size()-1;i >= 0;i--)	cout<<num[i]<<" ";
		}
		cout<<endl;
		num.clear();
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值