題解:
這道題我做了挺長時間了(看起來挺簡單的,但是做起來還是有點難度),結果還只有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;
}