091128日志(博客园博客显示数学公式的方法!)

这两天我把 blog 的数学公式显示的支持方案修改了下。

之前采用的是 ASCIIMathML.js 的方式来支持博客页面上的数学公式显示(这里有说明),但这个方法有几个不足之处:

  • 首先是 JS 脚本的大小问题,ASCIIMathML.js 这个脚本有 150K 左右,如果在 blog 中使用这个 JS 脚本的话,那么无论是否需要支持数学公式,访问者打开我的博客的页面的时候,都需要承受这 150K 的下载负担,对于网速好的访问者来说也许问题不大,但毕竟不少地方网速还不行(想起一年前十几户人共用 1M 网络的日子了,唉),所以这个脚本还是有点大了。
  • 使用 ASCIIMathML.js 脚本,会将页面上的数学公式转换成 ML 标签,要求浏览器必须要有支持,FireFox 等自然是没问题,但 IE 的用户则必须安装 MathPlayer 才能“正常”查看。
  • 最终产生的公式样子比较丑……

综上,感觉 ASCIIMathML.js 比较符合本机使用,嘿嘿,比如自己的 TW ……

新的方案是使用 MathTran 提供的公式转图片的服务,最初知道这个方法是因为我想在 TiddlyWiki 中使用数学公式显示,结果查到这么一篇文章,里面就有对 MathTran 的一些说明,按他说的方法试了试,确实很不错,显示的公式很漂亮。而且速度也很快。但原始的方法中有一个不足之处:必须在自己的页面中插入 <img> 标签,才能使用 mathtran 提供的脚本来转换。这很不方便,因为现在我基本上都是用 WLW 离线写文章,然后再进行发布,WLW 中直接编辑 html 代码当然是没问题的,但在“所见即所得”的编辑器中使用起来就很不爽了(你会看到文章中插入了一陀很难看的东西),如果公式的数量非常多的话,修改和编辑都不舒服,并且,评论栏要添加数学公式也不方便。要是能像 ASCIIMathML.js 那样多好啊。顺着这个想法,结合那篇文章中的作者也提到的“不过通过研究那个js可以再简化一点,直接使用端口 "http://www.mathtran.org/cgi-bin/mathtran?tex="+encodeURIComponent(expr),省去查错的环节。”于是我照虎画猫,抄了 ASCIIMathML.js 的一些代码,自己写了一点 JS 脚本,让这个脚本寻找正文和评论中两个反单引号之间的内容,自动生成 img 标签,这样,我在 WLW 中写东西时候就可以直接在编辑窗口写公式,发布后自然会被转成图片来显示,下面是这个 JS 的脚本的代码(12月1日更新):

// 将letax公式的文字生成一个img标签
function GenerateMathImg(formula) {
    var mi =document.createElement("img");    
    mi.src = "http://www.mathtran.org/cgi-bin/mathtran?tex=" 
        + encodeURIComponent(formula);
    mi.alt = formula;
    return mi;
}

function ProcessFormula(str, newFrag) {
    while (1) {
    // 将含有公式的文字块变换成= 文字块+公式img+文字块
        var re = str.match(/([^\`]*)\`(.*?)\`(.*)/);  
        if (re != null) {
            newFrag.appendChild(document.createTextNode(re[1]));
            newFrag.appendChild(GenerateMathImg(
                re[2].replace(/^\s+|\s+$/, '')));
            str = re[3];
        }
        else {
            newFrag.appendChild(document.createTextNode(str));
            break;
        }
    }
}

function processTextNode() {
    var nodeText = this.nodeValue;   
    if (nodeText.indexOf('`') != -1) {
        var strAry = nodeText.split("\\`");
        var newHtmlFrag = document.createDocumentFragment();
        for (var i = 0; i < strAry.length; ++i) {
            if (i > 0) {
                newHtmlFrag.appendChild(document.createTextNode("`"));
            }
            ProcessFormula(strAry[i], newHtmlFrag);            
        }
        this.parentNode.replaceChild(newHtmlFrag, this);  
    }   
    
}

function StartConvert() {
    var bConv = ($(document.body).html().indexOf('`') != -1);
    if (bConv) {
    // 找出页面上所有的text-node,对每个text-node调用processTextNode
    var allText = $(document.body).find("*").
        contents().filter(function(){
            return (this.nodeType == 3);
        }).each(processTextNode); 
    }
}

$(StartConvert)

不过现在这个脚本确实很简陋,也不知道有多少 bug,呵,先试着用着吧,等出了 bug 或是新需求再进一步调整。至少单行的公式显示应该是没有问题的,比如:

`f(x) = a_0 + \sum_{n=1}^\infty\left[a_n\cos(nx)+b_n\sin(nx)\right]`

傅立叶级数展开式,嘿嘿,:P。感觉还是不错的。嗯,美中不足的是博客模板的背景与公式图片的背景不一致,另外,如果把页面保存在本地,而又在查看的时候又不在连网状态的话,那就显示不了了(不过把脚本的代码删掉,会直接显示数学公式的,勉强可以接受吧……)。

记记别的。

编译原理的学习进展不大,上周又把词法分析复习了一遍,看语法分析的时候第一遍愣是没把上下文无关方法和 BNF 理解清楚,应该说是一头雾水,唉,真羡慕那些天才们,随手就写一个语言的编译器出来,仰望……,仰望完之后,下周继续看,读书百遍,其意自见嘛,我就不信我搞不明白它。

不过词法分析倒是理解得比较清楚了(毕竟这部分不太复杂嘛),哈哈,现在至少知道,如果要对 C/C++ 代码里的注释做些处理,用自动状态机的话其实也是很简单的。想以前用正则表达式来处理代码文件,处理的过程总是会出一些“意外”,毕竟正则表达式不懂“ C/C++ 语法”……表达能力也有限制。嗯,编译原理,继续学习,什么时候我也出个语言来玩玩,嘿嘿。

 

 

原文地址:https://www.cnblogs.com/muxue/p/1612732.html