思路
维护一个存标签的栈,依次读入每行,当读取到[
时
正常状态
读入完整标签,获取标签名(对url=xxx
和img=xxx
特判)
先考虑语法:
如果是开始标签,将标签名压入栈
如果是结束标签,与栈顶标签名不同则匹配失败,Match Error
语法无误后:
对于h1
类标签名,直接替换
对于url
和img
,用一个单独的栈存链接,在结束标签出输出链接
对于quote
进入quote
状态
quote
状态
继续向后读,如果读到[/quote]
就结束,否则正常输出
如果遍历完输入后,标签栈不是空的,则为Unclosed Mark
将输出先存在一个队列中,如果语法没有问题,最后依次输出并忽略空行(即"> "
和""
)
坑点
- 文末所说
由于洛谷限制,请大家在输出Unclosed Mark的时候在close中间切开分为两段字符串输出,否则会被吞记录。
是假的,正常输出才能AC
quote
中可能有[
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;
}