201703-3 Markdown

Markdown 是一种很流行的轻量级标记语言(lightweight markup language),广泛用于撰写带格式的文档。例如以下这段文本就是用 Markdown 的语法写成的:

image

  这些用 Markdown 写成的文本,尽管本身是纯文本格式,然而读者可以很容易地看出它的文档结构。同时,还有很多工具可以自动把 Markdown 文本转换成 HTML 甚至 Word、PDF 等格式,取得更好的排版效果。例如上面这段文本通过转化得到的 HTML 代码如下所示:

image

  本题要求由你来编写一个 Markdown 的转换工具,完成 Markdown 文本到 HTML 代码的转换工作。简化起见,本题定义的 Markdown 语法规则和转换规则描述如下:
  ●区块:区块是文档的顶级结构。本题的 Markdown 语法有 3 种区块格式。在输入中,相邻两个区块之间用一个或多个空行分隔。输出时删除所有分隔区块的空行。
  ○段落:一般情况下,连续多行输入构成一个段落。段落的转换规则是在段落的第一行行首插入 <p>,在最后一行行末插入 </p>
  ○标题:每个标题区块只有一行,由若干个 # 开头,接着一个或多个空格,然后是标题内容,直到行末。# 的个数决定了标题的等级。转换时,# Heading 转换为 <h1>Heading</h1>## Heading 转换为 <h2>Heading</h2>,以此类推。标题等级最深为 6。
  ○无序列表:无序列表由若干行组成,每行由 * 开头,接着一个或多个空格,然后是列表项目的文字,直到行末。转换时,在最开始插入一行 <ul>,最后插入一行 </ul>;对于每行,* Item 转换为 <li>Item</li>。本题中的无序列表只有一层,不会出现缩进的情况。
  ●行内:对于区块中的内容,有以下两种行内结构。
  ○强调:_Text_ 转换为 <em>Text</em>。强调不会出现嵌套,每行中 _ 的个数一定是偶数,且不会连续相邻。注意 _Text_ 的前后不一定是空格字符。
  ○超级链接:[Text](Link) 转换为 <a href="Link">Text</a>。超级链接和强调可以相互嵌套,但每种格式不会超过一层。
输入格式
  输入由若干行组成,表示一个用本题规定的 Markdown 语法撰写的文档。
输出格式
  输出由若干行组成,表示输入的 Markdown 文档转换成产生的 HTML 代码。
样例输入

1
2
3
4
5
6
# Hello

Hello, world!
样例输出
<h1>Hello</h1>
<p>Hello, world!</p>

评测用例规模与约定
  本题的测试点满足以下条件:
  ●本题每个测试点的输入数据所包含的行数都不超过100,每行字符的个数(包括行末换行符)都不超过100。
  ●除了换行符之外,所有字符都是 ASCII 码 32 至 126 的可打印字符。
  ●每行行首和行末都不会出现空格字符。
  ●输入数据除了 Markdown 语法所需,内容中不会出现 #*_[]()<>& 这些字符。
  ●所有测试点均符合题目所规定的 Markdown 语法,你的程序不需要考虑语法错误的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include<bits/stdc++.h>
using namespace std;
string parseLink(string a,string b){
string res="";
res+="<a href=\""+b+"\">"+a+"</a>";
return res;
}
string parseFocus(string t){
string res="<em>";
res+=t;
res+="</em>";
return res;

}
string parseL(string line){
string res="";
int i=0;
while(i<line.size()){
if(line[i]=='['){
int j=i+1;
while(line[j]!=']') j++;
string txt=line.substr(i+1,j-i-1);
assert(line[j+1]=='(');
i=j+1;
//!!
while(line[j]!=')') j++;

string link=line.substr(i+1,j-i-1);
string t1=parseL(txt);
string l1=parseL(link);
res+=parseLink(t1,l1);
i=j+1;
}
else if(line[i]=='_'){
int j=i+1;
while(line[j]!='_') j++;
string txt=line.substr(i+1,j-i-1);
string ntxt=parseL(txt);
res+=parseFocus(ntxt);
i=j+1;
}
else{
//!
res+=line[i];
i++;
}
}
return res;
}
string parsePa(vector<string> v){
string res="<p>";
for(int i=0;i<v.size();i++){
res+=parseL(v[i]);
if(v.size()!=0&&i!=v.size()-1) res+="\n";
}


res+="</p>\n";
return res;

}
string parseHeads(vector<string> v){
assert(v.size()==1);
string t=v[0];
int lev=1;
int i=0;
while(t[i]=='#') i++;
lev=i;
while(t[i]==' ')i++;
//substr的位置是i 不是i+1
string con=t.substr(i,-1);
con=parseL(con);
string res="";
char ss[10];
itoa(lev,ss,10);

res="<h"+(string)ss+">"+con+"</h"+(string)ss+">\n";
return res;
}

string parseU(vector<string> v){
string res="";
res+="<ul>\n";
for(int i=0;i<v.size();i++){
res+="<li>";
int j=0;
//!
if(v[i][j]=='*') j++;
while(v[i][j]==' ')j++;
res+=parseL(v[i].substr(j,-1));
res+="</li>\n";


}
res+="</ul>\n";
return res;
}
int main(){
string s;
int block;
vector<string> v;
string res="";
while(getline(cin,s)||v.size()>0)
{
if(s.empty()){
if(block!=0){
switch(block){
case 1:
res+=parseHeads(v);

break;
case 2:
res+=parseU(v);
break;
case 3:
res+=parsePa(v);
break;
default:
break;
}
//!!
v.resize(0);
block=0;
}

}
else if(s[0]=='#'){
v.push_back(s);
block=1;
}
else if(s[0]=='*'){
v.push_back(s);
block=2;

}
else{
v.push_back(s);
block=3;



}

}
cout<<res;

return 0;
}

复习了一遍 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include<bits/stdc++.h>
using namespace std;
string parseF(string w){
string rs="<em>"+w+"</em>";
return rs;
}
string parseLink(string txt,string link){
return "<a href=\""+link+"\">"+txt+"</a>";

}

string parseL(string line){
int i=0;
string rs="";
while(i<line.size()){
if(line[i]=='_'){
int j=line.find('_',i+1);
string w=line.substr(i+1,j-i-1);
w=parseL(w);
w=parseF(w);
rs+=w;
i=j+1;

}
else if(line[i]=='['){
int k=line.find("](",i+1);
int next=line.find(')',k+1);
string txt=line.substr(i+1,k-i-1);
string link=line.substr(k+2,next-k-2);
txt=parseL(txt);
link=parseL(link);
rs+=parseLink(txt,link);
i=next+1;
}
else{
rs+=line[i];
i++;
}
}
return rs;
}
string parseHead(vector<string> lines){
assert(lines.size()==1);
int i=0;
string line=lines[0];
while(line[i]=='#') i++;
int level=i;
while(line[i]==' ') i++;
string con=line.substr(i,-1);
con=parseL(con);
char ss[10];
itoa(level,ss,10);
string rs="<h"+(string)ss+">"+con+"</h"+(string)ss+">\n";
return rs;

}
string parseU(vector<string> lines){
string rs="<ul>\n";
for(int i=0;i<lines.size();i++){
rs+="<li>";
string ss=lines[i];
int j=0;
while(ss[j]=='*') j++;
while(ss[j]==' ') j++;
string w=ss.substr(j,-1);
rs+=parseL(w);
rs+="</li>\n";

}
rs+="</ul>\n";
return rs;

}
string parseP(vector<string> lines){
string rs="<p>";
for(int i=0;i<lines.size();i++){
rs+=parseL(lines[i]);
if(i!=lines.size()-1) rs+="\n";
}
rs+="</p>\n";
return rs;

}
int main(){
vector<string> vec;
string line;
int type=0;
string rs="";
while(getline(cin,line)||vec.size()>0){
if(line.empty()){
if(type!=0){

if(type==1){
rs+=parseHead(vec);
}
else if(type==2){
rs+=parseU(vec);
}
else if(type==3){
rs+=parseP(vec);
}
vec.resize(0);
type=0;
}
}
else if(line[0]=='#'){
type=1;
vec.push_back(line);
}
else if(line[0]=='*'){
type=2;
vec.push_back(line);
}
else {
type=3;
vec.push_back(line);
}

}

cout<<rs;
}