题意
给出一段 BBCode 格式的代码,让你将其转换为 Markdown 格式。
具体语法展示在题面中,其中减少了相当多的语法,并且对输入的代码作出了一些大大减轻码量的限制。
分析
如果是让你将一个没有语法问题的 BBCode 代码转换成 Markdown 代码,相信一定不难。对于除 quote
以外的指令,你可以使用直接替换的方式转换代码,如 [h1]
转换为 #
, [/b]
转换为 __
。而 quote
则相对难处理,因为 quote
块内可能出现其他的标识符,从而影响你的解析。事实上你只需要找到 [quote]
出现后的第一个 [/quote]
,然后将他们中间的部分拿出来直接作为 quote
块即可。
那么我们考虑可能存在语法错误的情况。
- 标签匹配错误:解决标签匹配错误最常规的方法,就是开一个指令栈。每当遇到一个起始标签,就将它压入指令栈;遇到一个结束标签,就检查指令栈的栈顶是否与它对应。如果不对应,则说明出现了
Match Error
情况。 - 标签未闭合:在上文指令栈的基础上,只需要在处理完整个输入之后判断一个指令栈是否不为空。如果不为空,则说明还有些标签是失配的,出现了
Unclosed Mark
情况。
毕竟是大模拟,细节处还需参见代码。
代码
/**
* @file P2395.cpp
* @author Macesuted
* @date 2020-12-21
*
* @copyright Copyright (c) 2020
*
*/
#include <bits/stdc++.h>
using namespace std;
//需压入指令栈的操作的对应值
#define val_h1 1
#define val_h2 2
#define val_i 3
#define val_b 4
#define val_url 5
#define val_img 6
#define bufferSiz 1 << 16
char B[bufferSiz], *_S = B, *_T = B;
#define getchar() (_S == _T && (_T = (_S = B) + fread(B, 1, bufferSiz, stdin), _S == _T) ? EOF : *_S++)
string output;//输出缓存
stack<int> cmdStack;//指令栈
stack<string> infoStack;//URL信息临时存储栈
void checkStack(int val)
{
if(cmdStack.empty()||cmdStack.top()!=val) puts("Match Error"),exit(0);//如果栈顶标签与此标签不同
return cmdStack.pop();
}
int main() {
char c=getchar();
while(c!=EOF)
{
if(c=='[')
{//开始读入标签
string cmd="";
c=getchar();
while(c!=']') cmd.push_back(c),c=getchar();
//此时已经读入完整的标签(在中括号中间的内容)
bool reverse=false;//false表示起始标签,true表示结束标签
if(cmd[0]=='/') reverse=true,cmd=cmd.substr(1);
if(cmd=="h1")
{//直接转换
if(!reverse) output.append("# "),cmdStack.push(val_h1);
else output.append(" #"),checkStack(val_h1);
}else if(cmd=="h2")
{//直接转换
if(!reverse) output.append("## "),cmdStack.push(val_h2);
else output.append(" ##"),checkStack(val_h2);
}else if(cmd=="i")
{//直接转换
output.push_back('*');
if(!reverse) cmdStack.push(val_i);
else checkStack(val_i);
}else if(cmd=="b")
{//直接转换
output.append("__");
if(!reverse) cmdStack.push(val_b);
else checkStack(val_b);
}else if(cmd.substr(0,3)=="url")
{
if(!reverse) infoStack.push(cmd.substr(4)),//由于URL信息在Markdown中后置,所以开栈临时存储
output.push_back('['),cmdStack.push(val_url);
else output.append("]("+infoStack.top()+")"),infoStack.pop(),checkStack(val_url);
}else if(cmd.substr(0,3)=="img")
{//与上面唯一的区别就是'['的左侧多了一个'!'
if(!reverse) infoStack.push(cmd.substr(4)),output.append("!["),cmdStack.push(val_img);
else output.append("]("+infoStack.top()+")"),infoStack.pop(),checkStack(val_img);
}else if(cmd=="quote")
{//由于quote的特殊性,这里一次性读到quote的结束标签
char c=getchar();
while(c=='\n'||c=='\r') c=getchar();//删除quote块的头部空行
string cache="";//cache临时存储读进来的所有内容
while(c!=EOF)
{
cache.push_back(c);
//如果cache字符串的末尾是"[/quote]",说明已结束
if(cache.size()>7&&cache.substr(cache.size()-8)=="[/quote]") break;
c=getchar();
}
if(c==EOF) { puts("Match Error"); return 0; }//如果读完了全文还没有读到结束标签
//比较愚笨的删除方法
cache.pop_back(),cache.pop_back(),cache.pop_back(),cache.pop_back(),
cache.pop_back(),cache.pop_back(),cache.pop_back(),cache.pop_back();
while(cache.back()=='\n'||cache.back()=='\r') cache.pop_back();//删除quote块的尾部空行
if(output.back()!='\n'&&output.back()!='\r') output.push_back('\n');//quote块前需有空行
output.append("> ");//以头部符号开始
for(string::iterator i=cache.begin();i!=cache.end();i++)
{
output.push_back(*i);
if(*i=='\n'||*i=='\r') output.append("> ");//每次换行都新增头部符号。
}
output.push_back('\n');//最后需要换行
}
}
else output.push_back(c);//如果是常规字符,则应该输出
c=getchar();
}
if(!cmdStack.empty()) { printf("Unclos"),puts("ed Mark"); return 0; }//如果指令栈没空
printf("%s\n",output.c_str());//输出缓存的输出
return 0;
}
Comments | NOTHING