c++TinML转html
前言
在python.tkinter设计标记语言(转译2-html)中提到了将TinML转为静态html的python实现方法;在HtmlRender - c++实现的html生成类中又提供了我自己写的基于c++编辑html的简单方式,这篇笔记就是使用c++将tinml转为静态html。
本示例未使用任何第三方库(除了我之前提供的HtmlRender类),但是在html中代码高亮方面使用了在线的highlight.js
。
整套流程下来和基于python的TinText平台类似,都是先解析TinML标记文本段,再给每个标记赋以特定含义(解释过程),最后通过这些解释后的内容生成html结构,生成html文本。
项目示例:CppTinParser: TinML to html by c++
解析
这一部分是对TinML标记的语法解析。
class TinLexer{
public:
TinLexer(string contents){
this->content = '\n' + contents + '\n';
}
void run_test();
vector<string> run();
vector<map<string,vector<string>>> lex();
private:
string content;
};
主要解析功能就是对每一行TinML标记文本段进行基于上下文标记的正则匹配和结构解析,这部分相当于TinText项目中的TinParser
:
- 单行TinML标记,分为标记名称和标记参数组
- 多行模式TinML,转为单行TinML标记解析后格式
部分代码如下:
vector<map<string,vector<string>>> TinLexer::lex(){
// 预处理
// tackle <tinfile>: add context of the specific TinML file into this->content
// 此部分代码省略,可见程序源码
// ...
vector<map<string,vector<string>>> tinresults;//总结果
vector<string> contents;
string nowtag;//当前标签
contents = split(this->content, '\n');
bool Lines = false;//多行模式
regex pattern("^<(.*?)>(.*)");
smatch result;
vector<string> args;//参数列表
for (const auto &i : contents){
if (size(i) == 1){
// 实际上是empty,不过貌似写不对
// 既有可能是因为getline将\n转为\0,导致该字符串截止
continue;
}
if (size(i)>=2 && i.substr(0,2)=="|-"){
// cout << "Comment: " << i << endl;
continue;
}
map<string,vector<string>> lineargs;//单行参数
if (Lines){
if (i[0]=='|'){
if (size(i)>2 && i[i.length()-2]!='|'){
string content = i.substr(1,size(i)-2);
args.push_back(subreplace(content, "%VEB%", "|"));
}else if (size(i)==2){
args.push_back("");
}else{
string content = i.substr(1,size(i)-3);
args.push_back(subreplace(content, "%VEB%", "|"));
// for (auto const &j : args){
// cout << "Arg: " << j << endl;
// }
lineargs[nowtag] = args;
tinresults.push_back(lineargs);
args.clear();
Lines = false;
}
}
}else if (i[i.length()-2] == ';'){
// getline最后一个为\0,因此-2
// string本身不以\0结尾,但是getline会改成\0
Lines = true;
bool ismatch = regex_search(i, result, pattern);
if (ismatch){
// cout << "Tag: " << result[1] << endl;
nowtag = result[1];
string content = result[2];
int lastindex = content.find_last_of(';');
content = content.substr(0, lastindex);
args.push_back(subreplace(content, "%VEB%", "|"));
}else{
cout << "\033[33;1m不可被解析,当作<p>处理:" << i << "\033[0m" << endl;
args.push_back(subreplace(i, "%VEB%", "|"));
lineargs["p"] = args;
tinresults.push_back(lineargs);
args.clear();
}
}else{
bool ismatch = regex_search(i, result, pattern);
if (ismatch){
nowtag = result[1];
string content = result[2];
auto oargs = split(content, '|');
for (auto const &j : oargs)
args.push_back(subreplace(j, "%VEB%",