TexSoup

repository·master·Indexed 43 days ago

https://github.com/alvinwan/texsoup

A fault-tolerant Python 3 package for searching, navigating, and modifying LaTeX documents by treating them as a searchable tree structure. Similar to BeautifulSoup, it parses LaTeX source code into a navigable hierarchy of TexNode objects, including TexCmd, TexEnv, and TexGroup, allowing for programmatic data extraction, format conversion, and document manipulation even with invalid LaTeX sources.

Tokens
7.1K
Snippets
28
Records
47
Agent score
55%

What's inside TexSoup

  1. What is TexSoup?

    master
    TexSoup is a Python 3 library designed for extracting data from $\LaTeX$ files. It parses $\LaTeX$ source code into a navigable, searchable, and modifiable structure similar to BeautifulSoup. A key feature is its ability to handle even invalid $\LaTeX$ sources by turning them into a structured format.
  2. Access environment contents and views

    master

    TexSoup provides several ways to view the contents of an environment or command. Use these attributes depending on whether you need to reconstruct the source exactly or just extract text.

    AttributeDescription
    .childrenNested Tex expressions. Does not include floating text.
    .contentsNested Tex expressions and text. Does not contain whitespace-only text.
    .expr.allAll information needed to reconstruct the original source (includes all whitespace).
    .descendantsTex expressions nested inside of other Tex expressions.
    .textReturns text from all descendants, stripping all Tex expressions (useful for "detexing").
    .stringIf a command has exactly one required argument (or an environment has one child), this returns that argument as a string.

    Warning: Modifying the .contents list in-place will not affect the actual environment structure.

    from TexSoup import TexSoup
    
    tex_doc = """
    \begin{document}
    \section{Hello \textit{world}.}
    \end{document}
    """
    soup = TexSoup(tex_doc)
    
    # Access the string argument of \textit
    print(soup.textit.string)  # Output: 'world'
    
    # Access all text without LaTeX commands
    print(soup.text)  # Output: 'Hello world.'
  3. Integrate TexSoup with LaTex2Python or Tex2Ipy

    master

    TexSoup powers several specialized conversion tools:

    • LaTex2Python (tex2py): Uses TexSoup to convert $\LaTeX$ into a document tree, organizing content based on a default or custom hierarchy.
    • Tex2Ipy: A tool by Prabhu Ramachandran that leverages TexSoup to convert $\LaTeX$ Beamer files into Jupyter notebooks.
  4. Understand TexSoup data structures

    master
    TexSoup represents LaTeX documents using a hierarchical tree of specialized data structures found in TexSoup.data. The core building blocks are TexNode objects, which can represent various LaTeX elements such as commands, environments, groups, and raw text. This tree structure allows for programmatic traversal and manipulation of LaTeX source code.
  5. Explore TexSoup usage examples

    master

    TexSoup can be used for a variety of $\LaTeX$ processing tasks, ranging from simple reference counting to complex document conversions. Key practical applications include:

    • Reference Counting: Counting occurrences of references within a document.
    • Format Conversion: Exporting $\LaTeX$ content to JSON or XML formats.
    • HTML Rendering: Converting $\LaTeX$ papers (e.g., from arXiv) into rich HTML.
    • Data Extraction: Parsing key-value groups and grouping text blocks.
    • Document Manipulation: Resolving imports and calculating solution lengths.

    Detailed implementation scripts for these use cases are available in the examples/ directory of the repository.

  6. Modify LaTeX environments

    master

    Environments can be modified using text-based or list-based operations:

    • Text-only environments: For environments containing only text (such as verbatim or math environments like \text{...}), use the .string attribute to replace the content.
    • Structural modifications: For environments containing multiple elements (like itemize), you can treat the environment's contents as a list. Use methods like .append(), .remove(), .insert(), and .extend() to add or remove elements (e.g., removing an \item and then re-inserting it elsewhere).
    >>> soup = TexSoup(r'\begin{verbatim}Huehue\end{verbatim}')
    >>> soup.verbatim.string = 'HUEHUE'
    >>> soup
    \begin{verbatim}HUEHUE\end{verbatim}
    
    >>> soup = TexSoup(r'$$\text{math}$$')
    >>> soup.text.string = ''
    
    >>> from TexSoup import TexSoup
    >>> soup = TexSoup(r'''
    ... \begin{itemize}
    ...     \item Hello
    ...     \item Bye
    ... \end{itemize}''')
    >>> tmp = soup.item
    >>> soup.itemize.remove(soup.item)
    >>> soup.itemize
    \begin{itemize}
    \item Bye
    \end{itemize}
    >>> soup.insert(1, tmp)
    >>> soup
    \begin{itemize}
    \item Hello
    \item Bye
    \end{itemize}
  7. Navigate up to a parent expression

    master

    To find the expression that contains the current one, use the .parent attribute.

    from TexSoup import TexSoup
    
    tex_doc = """
    \begin{document}
    \section{Hello \textit{world}.}
    \end{document}
    """
    soup = TexSoup(tex_doc)
    
    # Find the parent of the \textit command
    print(soup.textit.parent)  # Output: \section{Hello \textit{world}.}
  8. Search for commands and extract text

    master

    TexSoup provides utilities for searching specific patterns and extracting content:

    • Counting occurrences: Use .count(pattern) to find how many times a specific command or pattern appears.
    • Finding specific patterns: Use .find_all(pattern) to locate commands. For example, to find references, search for the \ref{label} pattern.
    • Line number mapping: Use soup.char_pos_to_line(cmd.position) to convert a command's character position into a (line, column) tuple.
    • Text extraction: Access the .text attribute to get a list of all text segments within the document, effectively stripping LaTeX commands.
    # Count and find references
    count = soup.count(r'\ref{table:synonyms}')
    for cmd in soup.find_all(r'\ref{table:synonyms}'):
        print(soup.char_pos_to_line(cmd.position))
    
    # Extract all text
    all_text = list(soup.text)
  9. Parse LaTeX documents with TexSoup

    master

    To parse a LaTeX document, pass the LaTeX string to the TexSoup constructor. This converts the string into a nested data structure that can be navigated and queried.

    from TexSoup import TexSoup
    
    tex_doc = """
    \begin{document}
    \section{Hello \textit{world}.}
    \end{document}
    """
    
    soup = TexSoup(tex_doc)
  10. Create a TexSoup from a file or string

    master

    To parse a $\LaTeX$ document, you can pass an open filehandle or a raw string into the TexSoup constructor. If you only want to compute the data structure without the full soup object, use the read function.

    To handle $\LaTeX$ documents with syntax errors, use the tolerance parameter in the TexSoup constructor. Setting tolerance=1 allows TexSoup to make a best-effort guess to parse the content despite errors.

    from TexSoup import TexSoup, read
    
    # From a filehandle
    with open("main.tex") as f:
        soup = TexSoup(f)
    
    # From a string
    soup2 = TexSoup(r'\begin{document}Hello world!\end{document}')
    
    # Compute data structure only
    soup3, _ = read(r'\begin{document}Hello world!\end{document}')
    
    # With error tolerance
    soup4 = TexSoup(r'\begin{itemize}\item hullo\end{enumerate}', tolerance=1)