继上文《在PowerPoint里优雅的插入LaTeX公式》后,没想到我又遇到了LaTeX相关的问题,这次是我博客无法正确的显示公式了。当然,最简单和粗暴的方法就是直接转成图片,但本着能折腾就折腾的精神,还是研究了一下如何优雅的解决。
#
问题复现
由于在LaTeX语法中,_
是用来表示下标,由于下标经常被使用,很容易就会导致一句话中出现两个_
。而在Markdown语法里,下划线是表示斜体的意思,于是Hugo就会将其转义成<em>
标签,导致公式格式错误,从而使KaTeX无法正确渲染。
这就很笨了,本地的Markdown编辑器都没有出现这样的问题,怎么到你Hugo这就拉了呢?
Is there any way to ignore underscore when rendering markdown? - support - HUGO (gohugo.io)
有这样问题的人也不止我一个,官方论坛上早在2017年就有人提问了,那么官方的答复是:
没错,官方并没有给出好的解决方案,只有在文档中稍微提到了一嘴,你可以使用pandoc
来进行Markdown的转义。
🤔本来用你就是图你的生成速度快,这调用其他程序后,这速度不就慢了没优势了吗。
没办法,还是自己动手解决吧。
#
解决方案
在搜索过后,网上给出的解决方案是在下划线前面加上\
,避免被Hugo进行转义。但是如果在写文档的时候就加上的话,就会导致本地公式无法正确渲染,所以边写边加是肯定不可能了。写完后手动添加,如果是一两个还好,但下划线在LaTeX里实在是太常用了,所以手工修改也不现实。
于是,我便决定写个小程序来自动修改。由于天天Apex大脑退化严重,我实在想不到什么比较好的字符串处理方法,只好用遍历大法。(这既视感,编译原理:……,什么……在想我的事情……?)
不玩梗了,直接上代码:
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
|
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
const bool DEBUG = false;
int main(int argc, char* argv[]) {
string file;
ifstream fin;
if (argc <= 1) {
cout << "请输入文件名称:";
cin >> file;
} else {
file = argv[1];
}
fin.open(file);
if (!fin.is_open()) {
cout << "无法打开文件" << endl;
system("pause");
return 1;
}
// 读入文件
string code((std::istreambuf_iterator<char>(fin)),
std::istreambuf_iterator<char>());
fin.close();
if (DEBUG) {
cout << code << endl;
cout << "-----------------" << endl;
}
// 所有数学公式的开头和结尾
vector<pair<int, int>> maths;
cout << "开始寻找所有数学公式" << endl;
for (int i = 0; i < code.length(); i++) {
if (code[i] == '$') {
i++;
bool is_double = false;
int start = i;
if (code[i] == '$') {
is_double = true;
i++;
start = i;
}
while (i < code.length() && code[i] != '$') {
i++;
}
if (is_double) {
i++;
}
if (i >= code.length() || code[i] != '$') {
cout << "错误:缺少结束符" << endl;
system("pause");
return 1;
}
int end = i;
maths.push_back(pair<int, int>(start, end));
cout << start << " " << end << endl;
if (DEBUG) {
string math = code.substr(start, end - start);
cout << math << endl;
}
}
}
cout << "寻找完成,开始处理" << endl;
int count = 0;
for (int i = 0; i < maths.size(); i++) {
for (int j = maths[i].first + count; j < maths[i].second + count; j++) {
if (code[j] == '_') {
code.insert(j, "\\");
count++;
j++;
} else if (code[j] == '\\') {
j++;
if (code[j] == '\\') {
code.insert(j, "\\\\");
count += 2;
j += 2;
} else if (code[j] == '{' || code[j] == '}') {
code.insert(j, "\\");
count++;
j++;
}
}
}
}
if (DEBUG) {
cout << code << endl;
}
cout << "处理完成,开始写入文件" << endl;
ofstream fout;
string location = file.substr(0, file.find_last_of('\\') + 1);
fout.open(location + "index.md");
if (!fout.is_open()) {
cout << "无法打开文件" << endl;
system("pause");
return 1;
}
fout << code;
return 0;
}
|
由于只是随手写的小工具,所以也没有分函数啥的,直接全放一起了。
这个程序会匹配$...$
和$$...$$
这两种格式,将其中所有的_
替换为\_
,所有的\\
替换为\\\\
,同时将文件在原位置保存为index.md
。
这样每次写好文章,只要将其拖到该程序上就能自动转换完成了。
这样就能确保本地查看编辑和网页都可以正确显示公式了。缺点则是每个有公式的文件都会多保存一份,不过文本文件并不是很大,所以也无伤大雅。
当然,这个程序还有优化的空间,比如自动对含有公式的文章进行处理等等。不过看这我文章更新的速度🕊️,手动拖一下还是可以接受的。
#
更新记录
2023.7.20:
2023.1.3: