# is there a python module for parsing LaTeX?

I am looking to write python programs that modify LaTeX source files. To do this I would like to have a basic parser in python that can reliably read and write LaTeX files while maintaining the tree. I'm okay if it is not a full implementation, but I need it to handle LaTeX's odd quoting rules and {} notation. Regular expressions simply do not work for this, due to the fact that braces can be recursive.

EDIT:

The main thing I want to handle is recursive braces, which is why I need a parser, rather than a simple lexical analyzer. That is, I want to be able to register \foo{} as a command I care about and catch:

\foo{this is the foo argument}


But I also want to be able to catch:

\foo{this is \emph{really} the foo argument}


Is there any such python module out there?

• I'm not aware of a library that can directly parse LaTeX and write it back to a file. One way (admittedly not very straightforward) might be to convert LaTeX to semantics-preserving xml with LaTeXML, read the xml with Python, and regenerate LaTeX using PyLaTeX. – Marijn Sep 27 '20 at 13:59
• Does LaTeXML->PyLaTeX guarantee a clean round-trip? – vy32 Sep 27 '20 at 14:00
• If you mean that the resulting .tex is the same as the original input file, then no. But depending on the actual use case this may still be a suitable approach. – Marijn Sep 27 '20 at 14:03
• You can try TeXSoup. However, there is yet to be a complete LaTeX parser that can fully handle macro definitions, catcodes, LaTeX3 and so on. – Alan Xiang Sep 27 '20 at 14:14
• there clearly can be no full parser try xii.tex (although actually latexml parses that with perl, which is quite a feat) but there will always be cases that require a full tex system to parse correctly. So it's a matter of how strict you want to be. Just parsing simple "latex book" document markup not tex macro code should be fairly easy. When you say "maintaining the tree" note latex never parses the full file and never constructs a tree. – David Carlisle Sep 27 '20 at 16:10

Please see if the LatexWalker class of pylatexenc can help:

from pylatexenc.latexwalker import LatexWalker

w = LatexWalker(r"\foo{this is \emph{really} the foo argument}")
(nodelist, pos, len_) = w.get_latex_nodes(pos=0)

print(nodelist[0].macroname)
print(nodelist[1].latex_verbatim())

>>> foo
{this is \emph{really} the foo argument}

• I tried to use your advice for this but quite complex apparently – JeT Dec 4 '20 at 11:00