欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Markdown转LaTeX的Python程序大全(持续更新)

程序员文章站 2022-07-02 18:47:45
...


Markdown是做笔记的利器,虽然有Pandoc这样的工具,但直接转过去的格式通常是没法直接编译成功的。其中一个最大的问题就是公式的转换。

比如在Markdown里面,写不写\begin{equation}这样的代码其实都不会自动编号,所以经常在做笔记的时候索性就不想写了。那么此时通常是用双$$符号来进行公式居中排版,而编号就手动用\tag{1}这样的方式进行。这种方式在Markdown里一时爽,但转成LaTeX\LaTeX的时候就非常痛苦了。转换过去的一大通代码无法编译,并且也不好改。当然还有一些非常不同于自己平时的操作,比如它会自动引用一些不太习惯的宏包。这种时候如果手动去修改工作量巨大。

在多次试验过后,发现最简单的方式还是将Markdown的正文部分直接粘到TeX\TeX的文件中,因为这样至少纯公式的部分就完全不用改动。至于作用域和环境的修改就手动弄一下就好。当然这种做法仍然是不够有效,尤其手动修改的时候十分容易出错,所以我们还是总结一些常用的方法,在从Markdown转向LaTeX\LaTeX的时候可以极大的节约我们的时间。

这个工作可能要一边做一边来完善,我们先将一些比较直接有效的方法列出,后续内容持续更新。

1.双$$符号转\begin-\end型公式

方法:思路很简单,将文本全部读出,依次将双$$改为\begin{equation}\end{equation}

def dollar2begin(input_fname,output_fanme):
    f = open(input_fname,'r')
    a = f.read()
    b= ''
    k = 1

    for i in range(100):
        if k%2 ==1:
            b = a.replace("$$",r"\begin{equation}",1)
        else:
            b = a.replace("$$",r"\end{equation}",1)
        a = b
        k += 1
        

    f2 = open(output_fanme,'w')
    f2.write(b)
    f2.close()
    f.close()

调用方式:

input_fname = r'test_input.md'
output_fanme = r'test_output.md'
dollar2begin(input_fname,output_fanme)
2.将\matrix{}域替换为\begin-\end

方法:这个功能的实现稍嫌复杂,涉及好几个问题。首先定位\matrix所在位置,然后定位其后的第一个左括号{ ,这2步相对好实现。而最难的在于找到和左括号完全对应的右括号},这里则需要一定的技巧。所以这里先写出括号匹配的方法,再写出完整的替换代码。

 def getIndex(s, i, targets=['{','}']): 
    if s[i] != targets[0]: 
        return -1
    d = deque() 
    for k in range(i, len(s)): 
        if s[k] is targets[1]: 
            d.popleft() 

        elif s[k] is targets[0]: 
            d.append(s[i]) 
        if not d: 
            return k 
    return -1

输入值:s为原字符串,i为第一个左括号所在的位置,targets表示对应的左手括号。这里写成这样是为了方便其它的作用域修改。比如还可以对方括、圆括甚至于其它的一些作用域。这里实现时采用了双队列,逐步将左括加入,如果遇到右括则匹配成功删除这一对(有点像对对碰)。那么当消除到最后一对时,即找到了想要的右括。由于deque是系统自带,因此可以不用导入相应的库。

完整的\matrix转换方法:

 def change_brackets(org_str, targname =r'\matrix',target_str = [r'\begin{matrix}',r'\end{matrix}']):
    first_ind = 0
    while True:   
        # find the sub_ind of the first bracket after targname
        left_brack = org_str.find(targname,first_ind) + len(targname)
        
        if left_brack > len(targname):
        # find the corresponding right bracket
            right_brack = getIndex(org_str,left_brack)
            org_str = org_str[0 : left_brack : ] +' '+ org_str[left_brack + 1 : :] 
            org_str = org_str[0 : right_brack : ]+target_str[1]+org_str[right_brack + 1 : :]             
            org_str = org_str.replace(targname,target_str[0], 1)
            first_ind = right_brack + 1
        else:
            break
    return org_str

这里为了方便起见,仍然将targname写成了默认类型,同时也对目标域的值进行了指定,所以也可以用于将其它类型进行修改。不过暂时还没发现哪些需要被修改的类型。

3.删除LaTeX\LaTeX中不需要的Markdown关键词

这里主要指的就是\tag{0},这一步操作很简单,因为我们编号的时候自己会有一个编号的习惯,所以可以自行将tag中的数值进行枚举再替换。当然最简单的就是用正则,一步到位。这里我们只写一个简单的实现方式,主要是为了写成一个统一的程序时能够方便地一步到位,而不用到处粘来粘去。

def remove_tags(org_str,targname = r'\tag'):
    i = 0 
    first_ind = 0
    while True:   
        # find the sub_ind of the first bracket after targname
        left_brack = org_str.find(targname,first_ind) + len(targname)

        if left_brack > len(targname):
        # find the corresponding right bracket
            right_brack = getIndex(org_str,left_brack)
            org_str = org_str.replace(org_str[left_brack-len(targname):right_brack+1],'')
            i += 1
            print(i)
        else:
            break
    return org_str

这里同样,虽然本意只是为了替换掉\tag{},但同样也可以用于其它同类型的关键词的替换。尤其这个方法可以将任意\label_name{XXX}这种样子的东西全部删掉,可以根据自己的需要进行调整即可。

目前基本上经过上述3步操作,所有在Markdown里能够正常显示的公式就能全部在\LaTeX中直接粘贴使用了。后续如果还有其它的发现,还会继续更新。