Estou usando a biblioteca MathQuill para oentrada de fórmulae tentando restringir uma série de operações. Existe alguma maneira que eu possadiferenciar entre uma string e uma regra LaTex?
Por exemplo:
def check('\sum') => True #LaTex rule
def check('\myCustomVar') => False #NOT a LaTex rule
Qualquer ajuda será apreciada!
Responder1
Pelo menos no Linux (não sei sobre o Windows), existe o latexdef
script de Martin Scharrer, que procura definições de LaTeX na linha de comando:
latexdef section
irá imprimir
\section
\long macro:->\@startsection {section}{1}{\z@ }{-3.5ex \@plus -1ex \@minus -.2ex}{2.3ex \@plus .2ex}{\normalfont \Large \bfseries }
enquanto
latexdef sausage
irá imprimir
\sausage
undefined
Podemos invocar latexdef
do Python assim:
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')
Isso 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 invocação latexdef
é bastante lenta, mas pode-se economizar tempo procurando vários comandos em uma única chamada. Este é o propósito do are_commands
, que retorna o resultado da pesquisa para cada comando em um dict.
Observe também que latexdef
é um script Perl, portanto, dependendo de quão importante isso é para você, pode fazer sentido traduzir tudo para Python, eliminando assim o intermediário. Mas é um roteiro longo, e Perl é meio difícil de ver...
Responder2
Esta não é uma resposta real, mas sim um comentário mais longo. A resposta dada por Michael Palmer funciona na maioria dos casos se essas macros forem definidas pelos pacotes/classes principais.
No entanto: Existem alguns casos que você pode querer considerar. Uma regra LaTeX como você a formula provavelmente significa sequência de comandos. A sequência de comandos típica do LaTeX (chamarei de "cmd" nos exemplos a seguir) pode ser produzida como o seguinte ABNF:
cmd = "\" 1*ALPHA
Mas isso não é suficiente. Você deve observar que existem macros internas que você pode querer incluir/excluir separadamente. Isso significaria que você teria que verificar algo como
cmd = "\" 1*(ALPHA | "@")
para macros internas. Se tal sequência de comandos for válida no ponto em que é usada, depende do contexto. Embora esta regra verifique a validade do comando em si, ela geralmente deve ser usada dentro de um \makeatletter ... \makeatother
ambiente para ser válida (se sua verificação envolver contexto).
E que sua verificação deve envolver contexto pode simplesmente ser mostrado por um comando como \frac
o qual é apenas uma "regra LaTeX válida" quando usado no modo matemático. Ou algo parecido \meter
que só é válido nos siunitx
comandos do.
Outro caso é exp3. Os comandos l3 também são válidos no LaTeX se estiverem entre \ExplSyntaxOn
e \ExplSyntaxOff
. Eles seriam construídos com algo assim:
cmd = "\" 1*(ALPHA | "_") ":" 0*ALPHA
o que na verdade não é verdade, pois os caracteres após os dois pontos são restritos, mas deve ser suficiente.
E fica ainda pior se você quiser verificar a validade das macros definidas pelo usuário, \csname ...\endcsname
pois o usuário tem muito mais opções aqui.
Atualizar:Afinal, o mais interessante seria verificar também se a chamada é válida. Isso significaria que você também teria que verificar a assinatura da função e depois a chamada do comando. Isso significaria que \frac
só seria válido se fosse chamado no modo matemático e tivesse dois argumentos obrigatórios. Fi gosto $\frac{1}{2}$
. Esse é o ponto onde você provavelmente deseja compilar um documento de amostra, porque um analisador real seria muito complexo aqui.
Todos esses métodos têm uma ressalva: você não obterá apenas sequências de comandos LaTeX, mas também sequências de comandos TeX. Se você tentar obter especificamente os do LaTeX, mas quiser excluir os do TeX, terá um problema.
Atualização 2:Como você estava interessado na implementação de um teste: Aqui estão algumas expressões regulares que você pode usar para fazer a correspondência. Somente na partida completa você terá uma sequência válida à sua frente. Para a parte sensível ao contexto, você pode querer trabalhar com lookaheads e lookbehinds.
- LaTeX padrão:
\\[A-Za-z]*
- LaTeX interno:
\\[A-Za-z@]*
- sintaxe exp:
\\[A-za-z@_]*:[DNncVvoOxfTFpw]*
\csname
comandos: algo como\\.*$