程序化转换/解析LaTeX代码为纯文本
我有几个用C++和Python写的代码项目,这些项目使用LaTeX格式的描述和标签来生成PDF文档或者用LaTeX和pstricks制作图表。不过,我们也有一些普通文本输出,比如文档的HTML版本(我已经有代码可以写出最简单的标记)和一个不支持TeX的图形渲染器。
对于这些输出,我想去掉一些为了表示物理单位而必须的TeX标记。这包括不换行的(细)空格、\text、\mathrm等。能把像\frac{#1}{#2}这样的内容简化成#1/#2用于普通文本输出(并在HTML中使用MathJax)也不错。由于我们现在的系统,我需要能从Python中做到这一点,也就是说,我理想中是找一个Python包,但如果有一个非Python的可执行文件,我可以从Python调用并获取输出字符串,那也可以。
我知道在TeX StackExchange网站上有一个类似的问题,但没有什么真正的编程解决方案。我看过detex、plasTeX和pytex,它们似乎都不太活跃,也没有真正满足我的需求:将TeX字符串程序化地转换为一个代表性的普通文本字符串。
我可以尝试用比如pyparsing写一个基本的TeX解析器,但a) 这可能会有很多坑,帮助会很受欢迎;b) 肯定有人之前尝试过,或者知道如何直接与TeX连接以获得更好的结果?
更新:感谢所有的回答……这确实是个有点尴尬的请求!我可以接受对LaTeX的解析不那么全面,但考虑使用解析器而不是在循环中用一堆正则表达式的原因是,我想能够很好地处理嵌套宏和多参数宏,并且让大括号匹配正常工作。这样我就可以先处理像\text和\mathrm这样的与文本无关的宏,最后处理像\frac这样的与文本相关的宏……也许还可以加上合适的括号!好吧,我可以做个梦……目前正则表达式的效果还不错。
再次更新:很长一段时间,我都是通过拼接所有需要的字符串,然后传给pandoc来处理我们的用例!虽然这样很糟糕,但对于我们不太重要的命令行美化来说,效果还不错……直到拼接的字符串变得太长!与此同时,pydetex(https://pydetex.readthedocs.io/en/latest/)出现了,成为另一个竞争者,参考TeXSoup,如果你能通过正则表达式或简单替换扩展足够的\def
。
8 个回答
虽然这个老话题有点久了,但我发现了一个很不错的库,叫做 pylatexenc
,它似乎正好能满足提问者的需求:
from pylatexenc.latex2text import LatexNodes2Text
LatexNodes2Text().latex_to_text(r"""\
\section{Euler}
\emph{This} bit is \textbf{very} clever:
\begin{equation}
\mathrm{e}^{i \pi} + 1 = 0 % wow!!
\end{equation}
where
\[
\mathrm{e} = \lim_{n \to \infty} \left(1 + \frac{1}{n}\right)^n
\]
""")
这个库可以生成
§ EULER
This bit is very clever:
e^i π + 1 = 0
where
e = lim_n →∞(1 + 1/n)^n
如你所见,结果在公式方面不是完美的,但它在去除和转换所有的tex命令方面做得非常好。
有一点需要注意:写一个完整的普通TeX解析器比你想象的要难得多。TeX级别的(不是LaTeX)\def
命令实际上是扩展了TeX的语法。比如,\def\foo #1.{{\bf #1}}
会把\foo goo.
变成goo——注意,句点变成了foo宏的分隔符!所以,如果你需要处理任何形式的TeX,而不限制可以使用哪些包,那么依赖简单的解析是不推荐的。你需要TeX渲染。catdvi是我使用的工具,虽然它并不完美。
我知道这是一篇旧帖子,但因为这个帖子在搜索latex-python-parsing时经常出现(可以从提取arXiv文章中的正文文本,格式为.tex看出来),所以我把它留在这里,方便后面的人参考:这里有一个用Python写的LaTeX解析器,它支持对解析树的搜索和修改,链接是https://github.com/alvinwan/texsoup。以下是从说明文档中摘录的示例文本,以及你如何通过TexSoup与它互动。
from TexSoup import TexSoup
soup = TexSoup("""
\begin{document}
\section{Hello \textit{world}.}
\subsection{Watermelon}
(n.) A sacred fruit. Also known as:
\begin{itemize}
\item red lemon
\item life
\end{itemize}
Here is the prevalence of each synonym.
\begin{tabular}{c c}
red lemon & uncommon \\
life & common
\end{tabular}
\end{document}
""")
下面是如何浏览解析树的方法。
>>> soup.section # grabs the first `section`
\section{Hello \textit{world}.}
>>> soup.section.name
'section'
>>> soup.section.string
'Hello \\textit{world}.'
>>> soup.section.parent.name
'document'
>>> soup.tabular
\begin{tabular}{c c}
red lemon & uncommon \\
life & common
\end{tabular}
>>> soup.tabular.args[0]
'c c'
>>> soup.item
\item red lemon
>>> list(soup.find_all('item'))
[\item red lemon, \item life]
声明:我写了这个库,但也是出于类似的原因。关于Little Bobby Tales的帖子(提到def
),TexSoup不处理定义。