Wie überprüft man, ob eine Zeichenfolge eine gültige LaTex-Regel ist?

Wie überprüft man, ob eine Zeichenfolge eine gültige LaTex-Regel ist?

Ich verwende die MathQuill-Bibliothek für dieFormeleingabeund versuche, eine Reihe von Operationen einzuschränken. Gibt es eine Möglichkeit,zwischen einem String und einer LaTex-Regel unterscheiden?

Zum Beispiel:

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

Jede Hilfe wird geschätzt!

Antwort1

Zumindest unter Linux (wie es unter Windows ist, weiß ich nicht) gibt es das latexdefSkript von Martin Scharrer, das LaTeX-Definitionen von der Kommandozeile aus nachschlägt:

latexdef section 

wird drucken

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

wohingegen

latexdef sausage 

wird drucken

\sausage
undefined

Wir können latexdefes von Python aus wie folgt aufrufen:

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')

Dieser Druck

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}

Jeder einzelne Aufruf von latexdefist ziemlich langsam, aber Sie können Zeit sparen, indem Sie mehrere Befehle in einem einzigen Aufruf nachschlagen. Dies ist der Zweck von are_commands, das das Suchergebnis für jeden Befehl in einem Dict zurückgibt.

Beachten Sie auch, dass es latexdefsich um ein Perl-Skript handelt. Je nachdem, wie wichtig es Ihnen ist, kann es sinnvoll sein, das gesamte Skript in Python zu übersetzen und so den Mittelsmann zu umgehen. Es ist jedoch ein ziemlich langes Skript und Perl ist ziemlich anstrengend für die Augen ...

Antwort2

Dies ist keine echte Antwort, sondern eher ein längerer Kommentar. Die Antwort von Michael Palmer funktioniert in den meisten Fällen, wenn diese Makros durch die Kernpakete/-klassen definiert werden.

Allerdings: Es gibt einige Fälle, die Sie berücksichtigen sollten. Eine LaTeX-Regel, wie Sie sie formulieren, bedeutet wahrscheinlich eine Befehlssequenz. Die typische LaTeX-Befehlssequenz (ich werde sie in den folgenden Beispielen „cmd“ nennen) kann als folgende ABNF erzeugt werden:

cmd = "\" 1*ALPHA

Aber das reicht nicht aus. Sie sollten beachten, dass es interne Makros gibt, die Sie möglicherweise separat ein-/ausschließen möchten. Das würde bedeuten, dass Sie nach etwas wie

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

für interne Makros. Ob eine solche Befehlssequenz zum Zeitpunkt ihrer Verwendung gültig ist, hängt vom Kontext ab. Obwohl diese Regel die Gültigkeit des Befehls selbst prüfen würde, muss er meistens in einer \makeatletter ... \makeatotherUmgebung verwendet werden, um gültig zu sein (wenn Ihre Prüfung den Kontext einbeziehen soll).

Und dass Ihre Prüfung einen Kontext einbeziehen sollte, lässt sich einfach durch einen Befehl wie \frac„der nur dann eine gültige LaTeX-Regel“ ist, wenn er im Mathematikmodus verwendet wird, oder etwas wie „ der nur innerhalb von Befehlen \metergültig ist“ anzeigen.siunitx

Ein anderer Fall ist expl3. l3-Befehle sind in LaTeX ebenfalls gültig, wenn sie in \ExplSyntaxOnund eingeschlossen sind \ExplSyntaxOff. Sie würden etwa so aufgebaut sein:

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

was eigentlich nicht ganz stimmt, da die Zeichen nach dem Doppelpunkt eingeschränkt sind, aber es sollte genügen.

Und noch schlimmer wird es, wenn man die Gültigkeit von benutzerdefinierten Makros darin überprüfen möchte, \csname ...\endcsnameda dem Benutzer hier wesentlich mehr Möglichkeiten zur Verfügung stehen.

Aktualisieren:Der interessanteste Teil wäre schließlich, auch zu prüfen, ob der Aufruf gültig ist. Das würde bedeuten, dass Sie auch die Signatur der Funktion und dann den Aufruf des Befehls prüfen müssten. Das würde bedeuten, dass er \fracnur gültig wäre, wenn er aus dem Mathematikmodus aufgerufen wird und zwei obligatorische Argumente hat. Fi wie $\frac{1}{2}$. Das ist der Punkt, an dem Sie wahrscheinlich ein Beispieldokument kompilieren möchten, da ein echter Parser hier sehr komplex wäre.

Alle diese Methoden haben einen Vorbehalt: Sie erhalten nicht nur LaTeX-Befehlssequenzen, sondern auch TeX-Befehlssequenzen. Wenn Sie gezielt versuchen, LaTeX-Befehlssequenzen zu erhalten, TeX-Befehle jedoch ausschließen möchten, treten Probleme auf.

Aktualisierung 2:Da Sie an einer Implementierung für einen Test interessiert sind: Hier sind einige reguläre Ausdrücke, die Sie zum Abgleichen verwenden können. Nur bei vollständiger Übereinstimmung haben Sie tatsächlich eine gültige Sequenz vor sich. Für den kontextsensitiven Teil möchten Sie möglicherweise mit Lookaheads und Lookbehinds arbeiten.

  • Standard-LaTeX:\\[A-Za-z]*
  • internes LaTeX:\\[A-Za-z@]*
  • expl-Syntax:\\[A-za-z@_]*:[DNncVvoOxfTFpw]*
  • \csnameBefehle: so etwas wie\\.*$

verwandte Informationen