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 latexdef
Skript 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 latexdef
es 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 latexdef
ist 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 latexdef
sich 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 ... \makeatother
Umgebung 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 \meter
gültig ist“ anzeigen.siunitx
Ein anderer Fall ist expl3. l3-Befehle sind in LaTeX ebenfalls gültig, wenn sie in \ExplSyntaxOn
und 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 ...\endcsname
da 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 \frac
nur 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]*
\csname
Befehle: so etwas wie\\.*$