分类
LaTeX

stackedit转为TeX表达式的正则替换规则

stackedit是一个比较好的在线数学编辑器, 可以随时写出漂亮的数学公式. 支持mathjax语法. 使用UserCustom extension中如下代码:

userCustom.onPagedownConfigure = function (editor) {
        var thmCounter  = { num: 0 };
        var excsCounter = { num: 0 };
        var environmentMap = {
            thm:   { title: "Theorem"    ,counter: thmCounter  },
            lem:   { title: "Lemma"      ,counter: thmCounter  },
            cor:   { title: "Corollary"  ,counter: thmCounter  },
            prop:  { title: "Property"   ,counter: thmCounter  },
            defn:  { title: "Definition" ,counter: thmCounter  },
            rem:   { title: "Remark"     ,counter: thmCounter  },
            prob:  { title: "Problem"    ,counter: excsCounter },
            excs:  { title: "Exercise"   ,counter: excsCounter },
            examp: { title: "Example"    ,counter: excsCounter },
            proof: { title: "Proof" },
            claim: { title: "Claim" }
        };
        var converter = editor.getConverter();
        // Save the preConversion callbacks stack
        var preConversion = converter.hooks.preConversion;
        converter.hooks.preConversion = function (text) {
            // Change \begin...\end to /begin.../end to avoid MathJax processing
            text = text.replace(/\\begin{(\w+)}([\s\S]*?)\\end{\1}/g, function (wholeMatch, m1, m2) {
                if(!environmentMap[m1]) return wholeMatch;
                // At this stage we need to keep the same number of characters for accurate section parsing
                return '/begin{' + m1 + '}' + m2 + '/end{' + m1 + '}';
            });
            // Transform \title and \section into markdown title to take benefit of partial rendering
            text = text.replace(/\\(\w+){([^\r\n}]+)}/g, function (wholeMatch, m1, m2) {
                // At this stage we need to keep the same number of characters for accurate section parsing
                if (m1 == 'section') {
                    // 1. 
has to be replaced by 10 chars
                    return '\n###     ' + m2 + '\n';
                }
                if (m1 == 'subsection') {
                    // 1.1. 
has to be replaced by 13 chars
                    return '\n####       ' + m2 + '\n';
                }
                if (m1 == 'subsubsection') {
                    // 1.1.1. has to be replaced by 16 chars
                    return '\n#####         ' + m2 + '\n';
                }
                if (m1 == 'title') {
                    //  has to be replaced by 8 chars
                    return '\n##    ' + m2 + '\n';
                }
                return wholeMatch;
            });
            // We are replacing the preConversion stack, call the other preConversion callbacks from the old stack
            return preConversion(text);
        };
        converter.hooks.chain("preBlockGamut", function (text, blockGamutHookCallback) {
            text = text.replace(/\(\w+):(\d+)/g, function (wholeMatch, m1, m2) {
                if(!environmentMap[m1]) return wholeMatch;
                return '<a class="latex_ref" href="#' + m1 + ':' + m2 + '">' + environmentMap[m1].title + ' ' + m2 + '</a>';
            });
            text = text.replace(/\\(author|date){([\s\S]*?)}/g, '<div class="latex_$1">$2</div>');
            return text.replace(/\/begin{(\w+)}([\s\S]*?)\/end{\1}/g, function (wholeMatch, m1, m2) {
                if(!environmentMap[m1]) return wholeMatch;
                var result = '<div class="latex_' + m1 + '"><span class="latex_title"></span>' + blockGamutHookCallback(m2);
                if (m1 == "proof") {
                    result += '<span class="latex_proofend" style="float:right">$■$</span>';
                }
                return result + '</div>';
            });
        });
        var previewContentsElt = document.getElementById('preview-contents');
        editor.hooks.chain('onPreviewRefresh', function() {
            thmCounter.num = 0;
            excsCounter.num = 0;
            _.each(previewContentsElt.querySelectorAll('[class^="latex_"]'), function(elt) {
                var key = elt.className.match(/^latex_(\S+)/)[1];
                var environment = environmentMap[key];
                if(!environment) return;
                var title = environment.title;
                if(environment.counter) {
                    environment.counter.num++;
                    title += ' ' + environment.counter.num;
                    elt.id = key + ':' + environment.counter.num;
                }
                elt.querySelector('.latex_title').innerHTML = title + '.';
            });
        });
    };

    userCustom.onReady = function () {
        var style = [
            '.latex_thm, .latex_lem, .latex_cor, .latex_defn, .latex_prop, .latex_rem, .latex_claim {',
            '    font-style:italic;',
            '    display: block;',
            '    margin:15px 0;',
            '}',
            '.latex_prob, .latex_examp, .latex_excs, .latex_proof {',
            '    font-style:normal;',
            '    margin: 10px 0;',
            '    display: block;',
            '}',
            '.latex_title {',
            '    float:left;',
            '    font-weight:bold;',
            '    padding-right: 10px;',
            '}',
            '.latex_proofend {',
            '    float:right;',
            '}',
        ].join('\n');
        $("head").append($('<style type="text/css">').html(style));
    };

可以非常容易的写出定理等环境: 例如/begin{thm}.../end{thm}, 可以看到与TeX的写法略有不同.

下面我利用WinEdt的正则表达式, 将上述/begin{thm}.../end{thm}转换为标准的\begin{thm}...\end{thm}.
设置如图所示, 然后点击Replace All即可.
reg_winedt_stackedit
需要注意的是WinEdt默认的就是非贪婪(non-greedy)模式, 这与传统的RegEx是不同的.

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据