CCF认证 201809-3元素选择器

本文介绍了一种基于C++的CSS选择器解析算法,通过使用unordered_map存储每一行的标签和ID选择器,实现了对CSS选择器的有效查找。文章详细解释了如何处理选择器的深度和大小写不敏感特性,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
思路就是根据题目的要求一步步模拟,比较简单,没有像别的博客一样建树,注释都在代码中,我认为需要注意的一点是标签的大小写不敏感。

#include <iostream>
#include <algorithm>
#include <string>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <unordered_map>
#include <map>
#include <vector>
using namespace std;
int main()
{
    int n, m;
    cin>>n>>m;
    unordered_map<int, vector<string> > mp;     //每一行到此行选择器的映射,第一个是标签选择器,第二个是ID选择器
    unordered_map<int, int> prio;   //每一行到此行深度的映射
    getchar();
    for(int i = 1 ; i <= n ; ++i)
    {
        string temp;
        getline(cin, temp);
        stringstream ss(temp);
        string str1, str2;
        ss>>str1;   //首先处理标签选择器
        int cnt = 0;
        int j;
        for(j = 0 ; j < str1.length() ; ++j)
        {
            if(str1[j] == '.')  //统计'.'的个数,记录深度
                cnt++;
            else
                break;
        }
        prio[i] = cnt;
        string ID = "";
        for(; j < str1.length() ; ++j)
            ID += tolower(str1[j]);     //将标签选择器全部置为小写,因为题上说大小写不敏感,这是一个坑点
        mp[i].push_back(ID);
        while(ss>>str2)
            mp[i].push_back(str2);  //将ID选择器存入map
    }
    for(int i = 0 ; i < m ; ++i)
    {
        string temp;
        getline(cin, temp);
        stringstream ss(temp);
        string str;
        vector<string> v;
        while(ss>>str)
        {
            if(str[0] != '#')   //如果不是标签选择器,那么处理
            {
                for(int j = 0 ; j < str.length() ; ++j)
                    str[j] = tolower(str[j]);
            }
            v.push_back(str);
        }
        bool flag = false;
        vector<int> ans;
        if(v.size() == 1)   //如果只查一个,单独处理
        {
            for(int k = n ; k >= 1; --k)
            {
                for(int t = 0 ; t < mp[k].size() ; ++t)
                {
                    if(mp[k][t] == v[0])
                    {
                        flag = true;
                        ans.push_back(k);
                    }
                }
            }
        }
        else
        {
            vector<int> st;
            reverse(v.begin(), v.end());    //从最深处开始查
            int cnt = 0;
            int init = 0, prePrio = 0;
            int flagNow = false;    //看最深处的选择器是否存在
            for(int k = n ; k >= 1 ; --k)
            {
                for(int t = 0 ; t < mp[k].size() ; ++t)
                {
                    if(mp[k][t] == v[0])
                    {
                        flagNow = true;
                        st.push_back(k);    //将最深处的选择器开始的位置记录下来
                    }
                }
            }
            if(flagNow) //如果存在
            {
                for(int j = 0 ; j < st.size() ; ++j)    //遍历这些最深处的选择器
                {
                  //  cout<<st[j]<<endl;
                    init = st[j];   //将最深处的选择器的位置设置为最终要存储的结果
                    prePrio = prio[st[j]];  //将深度初始化
                    cnt = 1;    //将当前找到的选择器个数初始化
                    for(int k = st[j] - 1; k >= 1 ; --k)    //从最深处开始从下往上寻找上一级的选择器
                    {
                        for(int t = 0 ; t < mp[k].size() ; ++t) //分别查询标签选择器和ID选择器
                        {
                            if(mp[k][t] == v[cnt])  //如果找到了
                            {
                                if(prio[k] < prePrio)   //并且深度比下一级浅
                                {
                                   // cout<<k<<endl;
                                    prePrio = prio[k];  //那么重置深度,以便寻找上一级
                                    cnt++;
                                    if(cnt == v.size())     //如果此时已找到个数已经满足要求
                                    {
                                        ans.push_back(init);
                                        flag = true;
                                        cnt = 0;
                                        goto now;
                                    }
                                }
                            }
                        }
                    }
                    now:;
                }
            }
        }
        if(!flag)
            cout<<0<<endl;
        else
        {
            cout<<ans.size();
            for(int j = ans.size() - 1 ; j >= 0 ; --j)
            {
                cout<<" "<<ans[j];
            }
            cout<<endl;
        }
    }
}
/*
 11 5
 html
 ..head
 ....title
 ..body
 ....h1
 ....p #subtitle
 ....div #main
 ......h2
 ......p #one
 ......div
 ........p #two
 p
 #subtitle
 h3
 body dIv #one p
 Div div div p p p
 
 
 */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值