题解P2395

· · 题解

思路

维护一个存标签的栈,依次读入每行,当读取到[

  1. 正常状态 读入完整标签,获取标签名(对url=xxximg=xxx特判) 先考虑语法:

    1. 如果是开始标签,将标签名压入栈
    2. 如果是结束标签,与栈顶标签名不同则匹配失败,Match Error

    语法无误后:

    1. 对于h1类标签名,直接替换
    2. 对于urlimg,用一个单独的栈存链接,在结束标签出输出链接
    3. 对于quote进入quote状态
  2. quote状态 继续向后读,如果读到[/quote]就结束,否则正常输出

如果遍历完输入后,标签栈不是空的,则为Unclosed Mark

将输出先存在一个队列中,如果语法没有问题,最后依次输出并忽略空行(即"> """

坑点

  1. 文末所说由于洛谷限制,请大家在输出Unclosed Mark的时候在close中间切开分为两段字符串输出,否则会被吞记录。是假的,正常输出才能AC
  2. quote中可能有[
  3. url,img中可能有/

代码

见注释

#include<bits/stdc++.h>
using namespace std;
queue<string>about_to_put;//只需要顺序遍历即可
stack<string>tags;//存标签
stack<string>ttemp;//存url/img,标签能嵌套
const string endquote="/quote]";
string tagname(string s){
    if(s[0]=='u')return "url";
    else if(s.length()>1&&s[0]=='i')return "img";
    return s;
}//获取正确的标签
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);//关闭流同步
    string s;
    bool quote=false;//是否正在quote
    while(getline(cin,s)){//依次读入每行
        string put;
        if(quote)put="> ";//quote前的`> `
        int t=s.length();
        for(int i=0;i<t;++i){//遍历字符串
            char c=s[i];
            if(c=='['){
                int j;
                if(quote){
                    //会有各种奇怪的坑:[quote][[[[[[[/quote]
                    string tttemp;
                    bool flag=false;
                    for(int k=1;k<=7;k++){
                        if(i+k==t){
                            i=t;
                            put+=("["+tttemp);
                            about_to_put.push(put);
                            put="";
                            flag=true;
                            break;//跳出大循环
                        }
                        tttemp+=s[i+k];
                    }
                    if(flag)break;
                    if(tttemp==endquote){
                        quote=false;
                        about_to_put.push(put);
                        put="";
                        tags.pop();//栈弹出 quote
                        i+=7;
                    }
                    else{
                        put+="[";
                    }
                    continue;
                }
                string temp;
                bool isclose=false;
                if(s[i+1]=='/')isclose=true;
                else temp+=s[i+1];//需要提前判断,因为url/img= 后面的东西可能会包含 /
                ++i;
                for(j=i+1;j<t;++j){
                    c=s[j];
                    ++i;
                    if(c==']'){
                        break;
                    }
                    //if(c=='/')isclose=true;
                    temp+=c;
                }
                /*
                if(quote&&(!isclose||temp!="quote")){
                    put+=("["+temp+"]");
                    continue;
                    //如果正在quote且不是关闭标签,直接导入
                }
                */
                if(isclose){
                    if(tags.empty()||tags.top()!=tagname(temp)){//匹配错误
                        //注意:||是短路运算符,把empty放前面,否则会RE!!!
                        cout<<"Match Error";
                        return 0;
                    }
                    tags.pop();
                }
                else tags.push(tagname(temp));
                if(temp=="h1"){
                    if(isclose)put+=" #";
                    else put+="# ";
                }
                else if(temp=="h2"){
                    if(isclose)put+=" ##";
                    else put+="## ";
                }
                else if(temp=="i")put+="*";
                else if(temp=="b")put+="__";
                else if(temp[0]=='u'){//url
                    if(isclose){
                        put+=("]("+ttemp.top()+")");
                        ttemp.pop();
                    }
                    else{
                        put+="[";
                        string tttemp=temp.substr(4);//截取 = 后部分
                        ttemp.push(tttemp);
                    }// [] 中的部分可以直接导入 about_to_put
                }
                else if(temp[0]=='i'){//img
                    if(isclose){
                        put+=("]("+ttemp.top()+")");
                        ttemp.pop();
                    }
                    else{
                        put+="![";
                        string tttemp=temp.substr(4);
                        ttemp.push(tttemp);
                    }
                }
                else{//quote
                    about_to_put.push(put);//换行
                    /*if(isclose){
                        quote=false;
                        put="";
                    }
                    else*/{
                        quote=true;
                        put="> ";//[quote]things...[/quote]
                    }
                }
            }
            else put+=c;
        }
        about_to_put.push(put);
    }
    if(!tags.empty())cout<<"Unclosed Mark";//仍有标签未关闭
    else{
        while(!about_to_put.empty()){
            string temp=about_to_put.front();
            about_to_put.pop();
            if(temp=="> "||temp=="")continue;//空行
            cout<<temp<<'\n';
        }
    }
    return 0;
}