¿Cómo comprobar si una cadena es una regla de LaTex válida?

¿Cómo comprobar si una cadena es una regla de LaTex válida?

Estoy usando la biblioteca MathQuill paraentrada de fórmulay tratando de restringir una serie de operaciones. ¿Hay alguna manera de que pueda¿Diferenciar entre una cadena y una regla de LaTex?

Por ejemplo:

def check('\sum') => True  #LaTex rule
def check('\myCustomVar') => False  #NOT a LaTex rule

¡Cualquier ayuda será apreciada!

Respuesta1

Al menos en Linux (no sé acerca de Windows), existe el latexdefscript de Martin Scharrer, que busca definiciones de LaTeX desde la línea de comandos:

latexdef section 

imprimirá

\section
\long macro:->\@startsection {section}{1}{\z@ }{-3.5ex \@plus -1ex \@minus -.2ex}{2.3ex \@plus .2ex}{\normalfont \Large \bfseries }

mientras

latexdef sausage 

imprimirá

\sausage
undefined

Podemos invocar latexdefdesde Python así:

import subprocess, re

def latexdef(command_list, *args):
    '''
    call latexdef on a list of commands to be looked up
    *args can be used to pass options to latexdef
    '''
    p = subprocess.Popen(['latexdef'] + list(args) + command_list, \
                        stdout=subprocess.PIPE, \
                        stderr=subprocess.STDOUT)
    return p.communicate()[0].strip()

def are_commands(command_list, *args):
    '''
    look up multiple commands and return results in a dict
    '''
    result = latexdef(command_list, *args)
    frags = [ f.splitlines() for f in re.split(r'\n{2,}', result, re.MULTILINE) ]
    return { command[1:] : defn != 'undefined' for command, defn in frags }

def is_command(command, *args):
    '''
    look up a single command
    '''
    return are_commands([command],*args).values()[0]

if __name__ == '__main__':
    commands = "chapter section sausage".split()

    for command in commands:
        print command, is_command(command)

    print "\nwith book class loaded"

    for command in commands:
        print command, is_command(command, '-c', 'book')

    print "\nall at once, with class book"
    print are_commands(commands, '-c', 'book')

Esto imprime

chapter False
section True
sausage False

with book class loaded
chapter True
section True
sausage False

all at once, with class book
{'sausage:': False, 'section:': True, 'chapter:': True}

Cada invocación de latexdefes bastante lenta, pero se puede ahorrar tiempo buscando varios comandos en una sola llamada. Este es el propósito de are_commands, que devuelve el resultado de la búsqueda para cada comando en un dict.

También tenga en cuenta que latexdefes un script Perl, por lo que dependiendo de lo importante que sea para usted, podría tener sentido traducir todo a Python, eliminando así al intermediario. Pero es un guión bastante largo, y Perl es un poco duro a la vista...

Respuesta2

Esta no es una respuesta real, sino más bien un comentario más largo. La respuesta dada por Michael Palmer funciona en la mayoría de los casos si esas macros están definidas por los paquetes/clases principales.

Sin embargo: hay algunos casos que quizás quieras considerar. Una regla de LaTeX, tal como la formulas, probablemente signifique una secuencia de comandos. La secuencia de comando típica de LaTeX (la llamaré "cmd" en los siguientes ejemplos) se puede producir como el siguiente ABNF:

cmd = "\" 1*ALPHA

Pero eso no es suficiente. Debe tener en cuenta que hay macros internas que quizás desee incluir o excluir por separado. Eso significaría que tendrías que comprobar algo como

cmd = "\" 1*(ALPHA | "@")

para macros internas. Si dicha secuencia de comandos es válida en el momento en que se utiliza, depende del contexto. Aunque esta regla verificaría la validez del comando en sí, \makeatletter ... \makeatotherpara que sea válida debe usarse principalmente dentro de un entorno (si su verificación implica contexto).

Y que su verificación debe involucrar contexto puede simplemente mostrarse mediante un comando como \fracel cual es solo una "regla LaTeX válida" cuando se usa en modo matemático. O algo así \meterque sólo es válido dentro de siunitxlos comandos.

Otro caso es expl3. Los comandos l3 también son válidos en LaTeX si están encerrados entre \ExplSyntaxOny \ExplSyntaxOff. Se construirían con algo como esto:

cmd = "\" 1*(ALPHA | "_") ":" 0*ALPHA

lo cual en realidad no es del todo cierto ya que los caracteres después de los dos puntos están restringidos, pero debería ser suficiente.

Y es aún peor si desea verificar la validez de las macros definidas por el usuario, \csname ...\endcsnameya que el usuario tiene muchas más opciones aquí.

Actualizar:Al fin y al cabo, lo más interesante sería comprobar también si la llamada es válida. Eso significaría que también tendrías que verificar la firma de la función y luego la llamada del comando. Eso significaría \fracque solo sería válido si se llama desde el modo matemático y tiene dos argumentos obligatorios. Me gusta $\frac{1}{2}$. Ese es el punto en el que probablemente desee compilar un documento de muestra, porque un analizador real sería muy complejo aquí.

Todos esos métodos tienen una advertencia: no solo obtendrás secuencias de comandos LaTeX, sino también secuencias de TeX. Si intenta específicamente obtener los de LaTeX pero desea excluir los de TeX, tendrá un problema.

Actualización 2:Como estaba interesado en la implementación para una prueba: aquí hay algunas expresiones regulares que puede usar para hacer coincidir. Sólo en una partida completa tendrás una secuencia válida frente a ti. Para la parte sensible al contexto, es posible que desee trabajar con búsquedas anticipadas y retrospectivas.

  • Látex estándar:\\[A-Za-z]*
  • Látex interno:\\[A-Za-z@]*
  • sintaxis explicativa:\\[A-za-z@_]*:[DNncVvoOxfTFpw]*
  • \csnamecomandos: algo como\\.*$

información relacionada