题解:
这道题我做了挺长时间了(看起来挺简单的,但是做起来还是有点难度),结果还只有70分。
我只说下我的过程:
1、只考虑区块(标题、无序列表、段落): 4个测点,正好拿了40分
2、考虑区块内的强调:多了两个测点,60分
3、考虑区块内的超链接:只多过了一个测点,应该是有错误,70分(最后的分数,懒得调试了)
注意点:
- 输出时删除所有分隔区块的空行,也就是没有空行
- 强调 和 超链接是行内,也就是是包括在区块中的(标题、无序列表、段落)
- 解题策略:拿到这种题目不要想着拿满分的,以这种思路去写代码,会完全的考虑大多数情况,但是实际上这样会很麻烦,还不如从最小的点开始,一步步的调试优化。
代码(70分)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <deque>
#include <list>
#include <utility>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <bitset>
#include <iterator>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0);
const double E = exp(1.0);
const int MOD = 1e9+7;
const int MAX = 1e5+5;
vector <string> markdown;
//vector <string> html;
// 将markdown的强调(其实就是斜体)形式转换为html形式:__item__ => <em>item</em>
bool judgeEmphasize(string mkdown)
{
// 判断有无强调(下划线)
int len = mkdown.length();
for(int i = 0; i < len; i++)
{
if(mkdown[i] == '_')
return true;
}
return false;
}
string emphasize(string mkdown)
{
int flag = 0;// 0 -> <em> 1 -> </em>
int len = mkdown.length();
int i = 0;
while(1)
{
/*
如果遇到'_' 且 flag = 0: 将'-'替换成"<em>"、flag = 1
如果遇到'_' 且 flag = 1: 将'-'替换成"</em>"、flag = 0
*/
if(mkdown[i] == '_')
{
if(flag == 0)
{
mkdown.replace(i,1,"<em>",4);
flag = 1;
i += 4;
}
else
{
mkdown.replace(i,1,"</em>",5);
flag = 0;
i += 5;
}
}
else
{
i++;
}
if(i == mkdown.length())
break;
}
return mkdown;
}
// 将markdown的超链接形式转换为html形式:[item](www.baidu.com) => <a herf="www.baidu.com">item</a>
string hyperlink(string mkdown)
{
int num = 0;// 计算'[' or ']' or '(' or ')'的数量,如果为偶数个即有超链接
int len = mkdown.length();
for(int i = 0; i < len; i++)
{
if(mkdown[i] == '[' || mkdown[i] == ']' || mkdown[i] == '(' || mkdown[i] == ')')
{
num++;
}
}
if(num % 2 != 0 || num == 0)
{
// 如果没有超链接,直接返回
return mkdown;
}
else
{
int index1,index2,index3,index4;
for(int i = 0; i < len; i++)
{
if(mkdown[i] == '[') index1 = i;
if(mkdown[i] == ']') index2 = i;
if(mkdown[i] == '(') index3 = i;
if(mkdown[i] == ')') index4 = i;
}
string str1 = mkdown.substr(index1+1,index2-index1-1);
string str2 = mkdown.substr(index3+1,index4-index3-1);
//cout << str1 << " " << str2 << endl;
string link = "<a href=\"";
link += str2 + '\"' + ">" + str1 + "</a>";
//cout << link << endl;
mkdown.replace(index1,index4-index1+1,(char *)link.c_str(),link.length());
return mkdown;
}
}
// 将markdown的段落形式转换为html形式:正常的分段 => <p></p>
void paragraph(int startRow,int endRow,int num)
{
/*
段落可能会有连续的几行,每一行放到一个string里面,
1. 如果只有一行 num = 1:
markdown[startCol]的前面要加个<p>,后面加个</p>
2. 如果有多行 num >= 2:
markdown[startCol]的前面要加个<p>,
markdown[endCol]的后面要加个</p>
*/
if(num == 1)
{
markdown[startRow] = "<p>" + markdown[startRow] + "</p>";
}
else
{
markdown[startRow] = "<p>" + markdown[startRow];
markdown[endRow] = markdown[endRow] + "</p>";
}
}
// 将markdown的标题形式转换为html形式:# => <h1></h1>
string itos(int i)
{
vector <int> tmp;
while(i)
{
tmp.push_back(i%10);
i /= 10;
}
string str = "";
int len = tmp.size();
for(int i = len - 1; i >= 0; i--)
{
str += ('0' + tmp[i]);
}
return str;
}
string title(string mkdown)
{
int index = 0;// 判断有几个'#'
while(mkdown[index] == '#') index++;
string content = mkdown.substr(index+1);
// 标题属于区块,区块就可能有强调或者超链接
content = hyperlink(content);
content = emphasize(content);
string res = "<h" + itos(index) + ">" + content + "</h" + itos(index) + ">";
return res;
}
// 将markdown的无序列表形式转换为html形式:* item => <ul> <li>item</li> </ul>
vector <string> unorderList(int startRow,int endRow,int num)
{
// 对于无序列表的处理:
vector <string> res;
res.push_back("<ul>");
for(int i = startRow; i <= endRow; i++)
{
int index = 0;
while(!isalnum(markdown[i][index]))
index++;
string tmp = markdown[i].substr(index); // 无序列表项属于区块,区块就可能有强调或者超链接
tmp = hyperlink(tmp);
tmp = emphasize(tmp);
res.push_back("<li>" + tmp + "</li>");
}
res.push_back("</ul>");
return res;
}
/* Markdown 文本到 HTML 代码的转换 */
int main()
{
/*
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
*/
string str;
while(getline(cin,str))
{
markdown.push_back(str);
}
int rowNums = markdown.size();
/*
for(int i = 0; i < rowNums; i++)
{
cout << markdown[i] << " " << markdown[i].size() << endl;
}
*/
int i = 0;
while(i < rowNums)
{
//cout << "i: " << i << " markdown[i][0]:" << markdown[i][0] << endl;
if(markdown[i][0] == '#')// 只考虑有标题
{
// cout << "标题的情况" << endl;
//html[i].push_back(title(markdown[i]);
cout << title(markdown[i]) << endl;
i++;
}
else if(markdown[i][0] == '*')// 如果遇到了列表,要看看下面有几个"*"
{
// cout << "列表的情况" << endl;
int num = 0;// 记录下"*"的个数
int j = i;
while(j < rowNums && markdown[j][0] == '*')
{
j++; num++;
}
// 这里可能要返回多行,所以用vector <string>来保存
vector <string> res(num+2);
res = unorderList(i,j-1,num);// 从markdown的i~j-1行,总共num个*,也就是num行数据
int len = res.size();
for(int k = 0; k < len; k++)
{
cout << res[k] << endl;
}
i = j;
}
else if(markdown[i].size() != 0)// markdown[i][0],也就是第一个字符,如果不是'#',也不是'*',那一定是段落的形式,前面后面加个<p> </p>
{
// cout << "段落的情况" << endl;
// 段落也要考虑有几行
int num = 0;
int j = i;
while(j < rowNums && markdown[j].size() != 0)
{
j++; num++;
}
// 调用段落函数以后吗,原数组markdown的行就会加上段落的标志
paragraph(i,j-1,num);
for(int k = i; k <= j-1; k++)
{
string tmp = markdown[k]; // 段落属于区块,区块就可能有强调或者超链接
tmp = hyperlink(tmp);
tmp = emphasize(tmp);
cout << tmp << endl;
}
i = j;
}
else
{
//cout << "空的情况" << endl;
i++;
}
}
/*
for(int i = 0; i < rowNums; i++)
{
cout << html[i] << endl;
}*/
return 0;
}