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 latexdef
script 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 latexdef
desde 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 latexdef
es 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 latexdef
es 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 ... \makeatother
para 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 \frac
el cual es solo una "regla LaTeX válida" cuando se usa en modo matemático. O algo así \meter
que sólo es válido dentro de siunitx
los comandos.
Otro caso es expl3. Los comandos l3 también son válidos en LaTeX si están encerrados entre \ExplSyntaxOn
y \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 ...\endcsname
ya 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 \frac
que 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]*
\csname
comandos: algo como\\.*$