程序设计二 大作业
设计一款软件可以把markdown语言转化成HTML语言。即输入markdown语言,软件输出HTML语言。软件需要将GFM规范中常用到的Text,Headers,List,Images,Links五项内容转化成HTML语言。从用户的角度出发,还要拥有GUI
一、设计思路打开文件(判断是否为markdown文件) 读取文件全部内容 输出html标签 选择写入的css样式 主题转换部分使用正则表达式 输出固定的结尾 二、转换方法 1. Text需要转化的正文部分有加粗,斜体,删除线,简单单行代码块,高亮 以加粗为例,则需要完成的转化为:
∗ ∗ i n f o ∗ ∗ ⇒ < b > i n f o < / b > **info** \ \Rightarrow \ <b>info</b> ∗ ∗ i n f o ∗ ∗ ⇒ < b > i n f o < / b >
转换时使用正则表达式(s为代转换字符串):
1 2 3 4 5 std::string temp, temp2; std::regex re_b ("\\*\\*([^\\*\\*]+)\\*\\*" ) ;temp = s; std::regex_replace (std::back_inserter (temp2), temp.begin (), temp.end (), re_b, "<b>$1</b>" ); s = temp2;
依次可完成加粗的转换,下面给出不同格式的正则表达式
1 2 3 4 5 6 7 std::regex re_i1 ("\\*([^\\*]+)\\*" ) ; std::regex re_i2 ("\\_([^\\_]+)\\_" ) ; std::regex re_S ("\\~\\~([^\\~\\~]+)\\~\\~" ) ; std::regex re_b1 ("\\*\\*([^\\*\\*]+)\\*\\*" ) ; std::regex re_b2 ("\\_\\_([^\\_\\_]+)\\_\\_" ) ; std::regex re_code ("\\`([^\\`]+)\\`" ) ; std::regex re_mark ("\\=\\=([^\\=\\=]+)\\=\\=" ) ;
需要完成的转换为:
# # ⋯ ⏟ n t e x t ⇒ < h n > t e x t < / h n > \underbrace{\#\#\cdots}_{n}\ \ text \Rightarrow \ <hn>text</hn> n # # ⋯ t e x t ⇒ < h n > t e x t < / h n >
所以需要先统计’#'出现的次数,再进行转换:
1 2 3 4 5 6 7 8 9 void tr_head (std::string s) { int index = 0 ; while (s[index] == '#' ) index++; std::smatch answer; std::regex_match (s, answer, std::regex ("^#{1,6} (.+)$" )); std::cout << "<h" << index << ">" << answer[1 ] << "</h" << index << ">" << std::endl; }
3. Images需要完成的转换
! [ n a m e ] ( u r l ) ⇒ < i m g s r c = ‘ ‘ u r l " >  \ \Rightarrow \ <img\ \ src=``url"> ! [ n a m e ] ( u r l ) ⇒ < i m g s r c = ‘ ‘ u r l " >
转换方法同前面类似,下面给出识别的正则表达式
1 std::regex re_image ("!\\[.+\\]\\((.+)\\)" ) ;
4. Links需要完成的转换
[ n a m e ] ( u r l ) ⇒ < a h r e f = ‘ ‘ u r l " > n a m e < / a > [name](url) \ \Rightarrow \ <a\ \ href=``url">name</a> [ n a m e ] ( u r l ) ⇒ < a h r e f = ‘ ‘ u r l " > n a m e < / a >
直接给出正则表达式
1 std::regex re_image ("\\[.+\\]\\((.+)\\)" ) ;
5. Lists整个翻译开始前先进行列表的递归搜索 先判断是否是列表,然后返回一个奇数或者偶数来代表判断返回的是有序列表还是无序列表,同时该数据还能储存空行数 若是列表,则判断与上一级的前面空格的关系,判断是否是新的一级列表,进入下一次递归,若上一级列表已经结束,则回溯到同一级列表处 整个列表结束时,返回,输出结尾的</ol>
或则和</ul>
,结束递归 具体的代码如下
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 int islist (int i) { int index = 0 ; std::regex a ("^[ ]*[-*+] (.+)$" ) ; std::regex e ("^[ ]*\\d+[.] (.+)$" ) ; if (std::regex_search (content[i], e)) { for (int j = 0 ; content[i][j] == ' ' ; j++) index++; if (index % 4 == 0 ) content[i] = std::regex_replace (content[i], e, "<li>$1</li>" ); else return -1 ; return 2 * index; } else if (std::regex_search (content[i], a)) { for (int j = 0 ; content[i][j] == ' ' ; j++) index++; if (index % 4 == 0 ) content[i] = std::regex_replace (content[i], a, "<li>$1</li>" ); else return -1 ; return 2 * index + 1 ; } else return -1 ; } int blankjudge (int a) { if (a % 2 == 0 ) return a / 2 ; else return (a - 1 ) / 2 ; } int handlelist (int i, int blanklast) { now = i; int blankthis = islist (i); if (blankthis == -1 ) return -1 ; else { int blankthis_temp = blankjudge (blankthis); int blanklast_temp = blankjudge (blanklast); if (blankthis % 2 == 0 ) { if (blankthis_temp > blanklast_temp || (blankthis_temp == blanklast_temp && blankthis != blanklast)) { content[i].insert (0 , "<ol>" ); int tmp = handlelist (i + 1 , blankthis); if (tmp == blankthis_temp) tmp = handlelist (now + 1 , blankthis); content[now - 1 ] += "</ol>" ; return tmp; } else if (blankthis_temp == blanklast_temp && blankthis == blanklast) { int tmp = handlelist (i + 1 , blankthis); return tmp; } else return blankthis_temp; } else { if (blankthis_temp > blanklast_temp || (blankthis_temp == blanklast_temp && blankthis != blanklast)) { content[i].insert (0 , "<ul>" ); int tmp = handlelist (i + 1 , blankthis); if (tmp == blankthis_temp) tmp = handlelist (now + 1 , blankthis); content[now - 1 ] += "</ul>" ; return tmp; } else if (blankthis_temp == blanklast_temp && blankthis == blanklast) { int tmp = handlelist (i + 1 , blankthis); return tmp; } else return blankthis_temp; } } return 0 ; }
6. Quotequote的转化和list基本相同,同时免去了有序无序的判断
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 int isquote (int i) { std::regex a ("^\\>+(.+)$" ) ; if (std::regex_match (content[i], a)) { int index = 0 ; while (content[i][index] == '>' ) index++; content[i] = std::regex_replace (content[i], a, "<p>$1</p>" ); return index; } else return 0 ; } void handlequote (int i, int last) { now = i; int number = isquote (i); if (number == 0 ) return ; else if (number >= last) { for (int j = 0 ; j < number - last; j++) content[i].insert (0 , "<blockquote>" ); handlequote (now + 1 , number); for (int j = 0 ; j < number - last; j++) content[now - 1 ] += "</blockquote>" ; } }
7. 分割线较为简单,直接给出转换函数
1 2 3 4 if (std::regex_search (s.at (i), std::regex ("^\\-{3,}$" ))) printf ("<hr/>\n" ); if (std::regex_search (s.at (i), std::regex ("^\\*{3,}$" ))) printf ("<hr/>\n" );
三、GUI的实现依托Qt实现程序的图形化,相关内容可查看源码
四、实验感想学习了markdown及html相关语法 熟悉了正则表达式的使用 熟悉了c++图形化界面的设计 五、源码 戳这里