P2395 BBCode 转换 Markdown 题解

· · 题解

简要题意

给你一段用格式语言 BBCode 书写的代码,且只含有 一级标题二级标题斜体文字粗体文字链接图片代码段 这几种格式。要求把这一段代码转换成用 Markdown 语言书写的格式代码。

思路

模拟题。但不知道为什么我居然能联想到 这道题。

为了方便处理,最好把输出存储在一个 string 里面。

而且出题人很仁慈地用这样一个样例来提醒我们:

[h1][i]Hello World![/h1][/i] //嵌套次序错误

一下子就看出来这些命令的正确嵌套顺序与栈的存储规则 完全一样

于是就可以用栈来存储命令信息(有一点像括号匹配)。

前面四个命令都可以用简短的几行代码来解决;但是后面三个不太好搞。

链接和图片,我们都可以用一个 string 类型的 来存储网址。

为什么还要用个栈啊?

因为毒瘤的 Markdown 允许用一张图片作为超链接的文字信息,就像这样:

[![](https://cdn.luogu.com.cn/upload/image_hosting/925awur2.png?x-oss-process=image/resize,m_lfit,h_170,w_225)](https://www.luogu.com.cn/user/387212)

可以尝试把上面这段格式代码粘贴到个人主页或云剪贴板,然后你就会发现这个很毒瘤的细节了。

最后就是代码段。

当我们检测到 [quote] 时,我们就要直接继续往下输入,用一个 string 来存属于代码段的字符,直到检测出 [/quote] 为止。

接下来有两个判断:

  1. 是否存在形如 [quote][/quote] 的情况(就是特判中间是不是空的,样例 6 需要用到)
  2. 在开始往输出的字符串中加入代码段时,要先判断前面有没有其他的文字,以此确定要不要换行(具体见样例 7,如果没处理好前面就会多空一行)

所有格式信息都转换完以后,我们还要判断,原先那个我们用来存储命令的栈是不是空的(如果不空,就说明要输出 Unclosed Mark)。

代码(核心)

代码中的 io.write() 是我自己定义的快写函数,改成自己喜欢的输出方式就可以了~

string Ans;
stack<int> CmdStack;
stack<string> InfoStack;
map<string,int> CmdMap;
inline void CheckStack(int val)
{
    if(CmdStack.empty()||CmdStack.top()!=val)
    {
        Ans="Match Error";
        io.write(Ans);
        exit(0);
    }
    CmdStack.pop();
}
signed main()
{
    CmdMap["h1"]=1;
    CmdMap["h2"]=2;
    CmdMap["i"]=3;
    CmdMap["b"]=4;
    CmdMap["url"]=5;
    CmdMap["img"]=6;
    char c=getchar();
    while(~c)
    {
        if(c=='[')
        {
            string Cmd;
            c=getchar();
            while(c!=']')
            {
                Cmd+=c;
                c=getchar();
            }
            bool tail=0;
            if(Cmd[0]=='/')
            {
                tail=1;
                Cmd=Cmd.substr(1);
            }
            if(Cmd=="h1")
            {
                if(!tail)
                {
                    Ans+="# ",
                    CmdStack.push(CmdMap[Cmd]);
                }
                else
                {
                    Ans+=" #";
                    CheckStack(CmdMap[Cmd]);
                }
            }
            else if(Cmd=="h2")
            {
                if(!tail)
                {
                    Ans+="## ";
                    CmdStack.push(CmdMap[Cmd]);
                }
                else
                {
                    Ans+=" ##";
                    CheckStack(CmdMap[Cmd]);
                }
            }
            else if(Cmd=="i")
            {
                Ans+='*';
                if(!tail)
                    CmdStack.push(CmdMap[Cmd]);
                else
                    CheckStack(CmdMap[Cmd]);
            }
            else if(Cmd=="b")
            {
                Ans+="__";
                if(!tail)
                    CmdStack.push(CmdMap[Cmd]);
                else
                    CheckStack(CmdMap[Cmd]);
            }
            else if(Cmd.substr(0,3)=="url")
            {
                if(!tail)
                {
                    InfoStack.push(Cmd.substr(4));
                    Ans+='[';
                    CmdStack.push(CmdMap[Cmd.substr(0,3)]);
                }
                else
                {
                    Ans+="]("+InfoStack.top()+")";
                    InfoStack.pop();
                    CheckStack(CmdMap[Cmd.substr(0,3)]);
                }
            }
            else if(Cmd.substr(0,3)=="img")
            {
                if(!tail)
                {
                    InfoStack.push(Cmd.substr(4));
                    Ans+="![";
                    CmdStack.push(CmdMap[Cmd.substr(0,3)]);
                }
                else
                {
                    Ans+="]("+InfoStack.top()+")";
                    InfoStack.pop();
                    CheckStack(CmdMap[Cmd.substr(0,3)]);
                }
            }
            else if(Cmd=="quote")
            {
                if(tail)
                {
                    Ans="Match Error";
                    io.write(Ans);
                    return 0;
                }
                char c=getchar();
                while(c=='\n'||c=='\r')
                    c=getchar();
                string Cache;
                while(c!=EOF)
                {
                    Cache+=c;
                    if(Cache.length()>7&&Cache.substr(Cache.size()-8)=="[/quote]")
                        break;
                    c=getchar();
                }
                if(Cache.length()>8)
                {
                    if(c==EOF)
                    {
                        Ans="Match Error";
                        io.write(Ans);
                        return 0;
                    }
                    rep(i,1,8)
                        Cache.pop_back();
                    while(Cache.back()=='\n'||Cache.back()=='\r')
                        Cache.pop_back();
                    if(Ans.length()&&Ans.back()!='\n'&&Ans.back()!='\r')
                        Ans+='\n';
                    Ans+="> ";
                    rep(i,0,Cache.length()-1)
                    {
                        Ans+=Cache[i];
                        if(Cache[i]=='\n'||Cache[i]=='\r')
                            Ans+="> ";
                    }
                    Ans+='\n';
                }
            }
        }
        else
            Ans+=c;
        c=getchar();
    }
    if(CmdStack.size())
    {
        Ans="Unclosed Mark";
        io.write(Ans);
        return 0;
    }
    io.write(Ans);
    return 0;
}