Como verificar se uma string é uma regra válida do LaTex?

Como verificar se uma string é uma regra válida do LaTex?

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 latexdefscript 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 latexdefdo 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 ... \makeatotherambiente 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 \fraco qual é apenas uma "regra LaTeX válida" quando usado no modo matemático. Ou algo parecido \meterque só é válido nos siunitxcomandos do.

Outro caso é exp3. Os comandos l3 também são válidos no LaTeX se estiverem entre \ExplSyntaxOne \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 ...\endcsnamepois 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 \fracsó 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]*
  • \csnamecomandos: algo como\\.*$

informação relacionada