MathJax常见问题
本文记录了在配置hexo博客和MathJax一起使用的多个问题及解决方法. hexo本身和数学公式的兼容性就不是很好, 所以发生了很多兼容性问题.
MathJax和英文小括号的冲突
如果你即使用了hexo也使用了MathJax, 那么有很大几率你会使用小括号来正常书写文章内容.
譬如:
This text is (in parenthesis) but it doesn’t work.
它会显示成:
This text is $in parenthesis$ but it doesn’t work.
起初, 我一度认为是MathJax的大括号冲突导致了某个地方的小括号也出了同样的渲染问题, 但后来发现问题完全跑偏了. 这个真的卡了我挺长时间的… 很多地方都没有记载过这个问题. 直到我看到了关于MathJax3.0版本的配置问题, 才找到一段额外管理内联公式的script, 那么2.7是不是也应该有相应的一段呢?
在blog\themes\hexo-theme-matery\layout\post.ejs
中, 有这样一段代码, 是用来调整内联公式的识别方式的. 如果不添加这段js, Mathjax只能识别大的公式, 而不能识别内联公式. 很明显, 这里直接就将转义后的()
小括号对也当做公式匹配范围了, 也就不难解释之前错误识别的情况.
<% if (theme.mathjax.enable && page.mathjax) { %>
<script src="<%- theme.mathjax.cdn %>"></script>
<script>
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$', '$'],['\(', '\)']]}
});
</script>
<% } %>
我们只要把['\(', '\)']
删去, 或者替换成更严格匹配的括号对['\\(', '\\)']
, 就能解决在博客markdown不能正确显示小括号内容的问题.
MathJax和Markdown冲突
Mathjax和Markdown的下划线语法冲了. 比如:
$$
w^{(l)}_{ij} = w^{(l)}_{ij} - \eta\frac{\partial E(W, b)}{\partial w^{(l)}_{ij}}
$$
它大概率会渲染不出来, 变成:
$$
w^{(l)}{ij} = w^{(l)}{ij} - \eta\frac{\partial E(W, b)}{\partial w^{(l)}_{ij}}
$$
这是因为Markdown和Mathjax的语法冲了, 这时候必须要修改blogtest\node_modules\marked\lib\marked.js
, 找到var inline
, 修改escape
和em
的正则匹配式:
var inline = {
escape: /^\\([`*\[\]()#$+\-.!_>])/,
// ...
em: /^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
// 去除了下划线_的斜体匹配
// ...
}
千万不要去装hexo-renderer-kramed
! 否则如果你安装了hexo-prism-plugin
, 也就是代码显示插件, 那这个代码高亮插件就崩了.
在更换escape
的正则后, 一定要避免的出现, 最起码要在其中加上一个空格变成
{ {
和} }
, 否则会编译报错.
我尝试过保留 escape
中对\\
的转义, 这样4个反斜杠才能换行, Typora
里写的时候会额外多空出来一行. 我这里在去掉这个\\
后, 在公式换行时仍然会莫名其妙有1个反斜杠被转义, 这样需要3个反斜杠才能换行, 在Typora
里会导致公式第二行多一个空格(实际渲染以后没有问题), 但比上面多换一行要强.
2020.08.11: 发现3个反斜杠在Typora
写表格时使表格无法正确显示.
还有一个很蛋疼的地方, 有些地方不能在公式中使用带有*
的字符, 会导致之后的内容变成斜体. 因为去掉了_
在公式中的正则, 那就只能通过*
来表示斜体. 虽然斜体我几乎不用, 但是星号是表示斜体唯一的方法了, 考虑到这个就没有把斜体的正则匹配也去掉.
2020.08.11: 今天在整理Markdown公式写法的时候, 意外发现了星号可以用\ast
代替! 于是这个问题也被解决了.
MiniValine冲突
2020.8.18: 当博客的mathjax
和minivaline
同时使用时, 会变得很卡. 这是因为minivaline
里的math
和博客公式显示的mathjax
有冲突. 把它关掉就行了.
minivaline:
enable: true
# ...
math: false # Support MathJax.
# ...
MathJax2迁移到MathJax3
其实MathJax
除了上面那些不太兼容的问题(确实有点恶心)来说, 没什么太大的毛病. 但是一旦公式多了就体现出来一个问题, 慢! 现在MathJax
已经更新到3.0及以上版本, 官方团队直接把2的代码重写了, 效率提高了60% ~ 80%, 这个速度还是非常诱人的.
There were a number of design goals to the version 3 rewrite. A primary one was to improve the rendering speed of MathJax, and we feel we have accomplished that. Because the two versions operate so differently, it is difficult to make precise comparisons, but in tests that render a complete page with several hundred expressions, we see a reduction in rendering time of between 60 and 80 percent, depending on the browser and type of computer.
更新版本
因为我用的是Matery
, 所以自己稍微改了改. 其他主题的更改方法大致相同.
先在主题下的_config.yml
文件中, 将之前的mathjax
连接的网址更换为最新的. 当然我这里直接采用了保留原来2.7的版本. 除了因为需要旧版本可以随时更换回来, 还有一个原因就是3.0的配置方法与2.7版本的配置方式是不同的, 这就意味着在渲染过程中的代码需要重新写一份, 没有必要把旧版本的内容完全删除.
mathjax:
enable2: false
enable3: true
cdn2: https://cdn.bootcss.com/mathjax/2.7.7/MathJax.js?config=TeX-AMS-MML_HTMLorMML
cdn3: https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
然后再去改渲染的脚本blogtest\themes\hexo-theme-matery\layout\post.ejs
, 并参考官方文档配置教程, 在末尾更改:
<% if (theme.mathjax.enable2 && page.mathjax) { %>
<script src="<%- theme.mathjax.cdn2 %>"></script>
<script>
MathJax.Hub.Config({
tex2jax: { inlineMath: [['$', '$'], ['\\(', '\\)']] } // 行内公式标识
});
</script>
<% } %>
<% if (theme.mathjax.enable3 && page.mathjax) { %>
<script id="MathJax-script" async src="<%- theme.mathjax.cdn3 %>"></script>
<script>
MathJax = {
tex: {
inlineMath: [['$', '$'], ['\\(', '\\)']]
}
};
</script>
<% } %>
这样在需要旧版本时候直接调整enable
就行了. 当然你还可以更改其他的配置, 参考教程即可.
无法换行
我换了以后发现一个问题, 多行公式开始变得没法换行了. 我已经排除掉了转义的问题, 确确实实已经有两个反斜杠, 可是公式没法换行.
测试了一会后, 发现无论多少反斜杠都没有办法换行, 我在官方issue找到了答案(有超多人有这个问题). 官方从旧版本迁移过来还没有实现换行符, 官方提到了两种办法来解决这个问题.
- 使用
\displaylines
.
$$
\displaylines{\lim_{N\to\infty}E(p_{max})=N\frac{1}{N}(1-\frac{1}{N})^{N-1} = \frac{(1-\frac{1}{N})^N}{1-\frac{1}{N}} \\
\lim_{N\to \infty}{1-\frac{1}{N}}=1 \qquad\lim_{N\to \infty}({1-\frac{1}{N}})^N=\frac{1}{e} \\
\lim_{N\to \infty}{E(p_{max})}=\frac{1}{e}=37\%}
$$
我当然比较倾向于用这种, 因为我不习惯下面那种编写方式, 在Typora
里实在是太麻烦了.
- 使用
{align}
或者{aligned}
.
$$
\begin{align}
x’ = \frac{x - x_{median}}{IQR} \\
IQR = x_{q3} - x_{q1}
\end{align}
$$
这种方式当然也有优点, 就是方便公式的对齐, 因为对齐时候必须要在多行公式的环境里面.
$$
\begin{aligned}
E(p)&=Np(1-p)^{N-1} \\
E’(p)&=N(1-p)^{N-1} -Np(1-p)^{N-2} \\
&=N(1-p)^{N-2}((1-p)-p(N-1))\\
E’(p)&=0 \Rightarrow p_{max}=\frac{1}{N}
\end{aligned}
$$
还发现了一些意外小惊喜:
WordPress uses
\
as a special character, and it is often stripped out of WordPress posts (depending on what editor you are using). As an escape character, it can prevent the normal action of the character that follows it, so to get an explicit backslash into your post, you need to double it. That is why you need an extra backslash (because the first two equal a single backslash in the output). You probably should double the second one as well, but apparently that is not required.
官方人员提到了WordPress中的类似问题, 我猜hexo第一个反斜杠被转义也是类似的原因.