Я использую библиотеку MathQuill дляввод формулыи пытаюсь ограничить количество операций. Есть ли способ, которым я могуразличать строку и правило LaTex?
Например:
def check('\sum') => True #LaTex rule
def check('\myCustomVar') => False #NOT a LaTex rule
Любая помощь будет оценена по достоинству!
решение1
По крайней мере, в Linux (насчет Windows не знаю) есть скрипт latexdef
Мартина Шаррера, который ищет определения LaTeX из командной строки:
latexdef section
напечатает
\section
\long macro:->\@startsection {section}{1}{\z@ }{-3.5ex \@plus -1ex \@minus -.2ex}{2.3ex \@plus .2ex}{\normalfont \Large \bfseries }
тогда как
latexdef sausage
напечатает
\sausage
undefined
Мы можем вызвать его latexdef
из Python следующим образом:
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')
Это печатает
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}
Каждый отдельный вызов latexdef
довольно медленный, но время можно сэкономить, выполнив поиск нескольких команд за один вызов. Это цель are_commands
, которая возвращает результат поиска для каждой команды в словаре.
Также обратите внимание, что latexdef
это скрипт Perl, поэтому в зависимости от того, насколько это для вас важно, может иметь смысл перевести все это на Python, таким образом убрав посредника. Но это довольно длинный скрипт, а Perl немного утомляет глаза...
решение2
Это не настоящий ответ, а скорее более длинный комментарий. Данный ответ Майкла Палмера работает в большинстве случаев, если эти макросы определены основными пакетами/классами.
Однако: Есть некоторые случаи, которые вы, возможно, захотите рассмотреть. Правило LaTeX, как вы его сформулируете, вероятно, означает последовательность команд. Типичная последовательность команд LaTeX (в следующих примерах я буду называть ее «cmd») может быть получена как следующая ABNF:
cmd = "\" 1*ALPHA
Но этого недостаточно. Вы должны отметить, что есть внутренние макросы, которые вы можете захотеть включить/исключить отдельно. Это означало бы, что вам придется проверить что-то вроде
cmd = "\" 1*(ALPHA | "@")
для внутренних макросов. Если такая последовательность команд действительна в точке ее использования, она зависит от контекста. Хотя это правило будет проверять действительность самой команды, в основном она должна использоваться в \makeatletter ... \makeatother
среде, чтобы быть действительной (если ваша проверка должна включать контекст).
И то, что ваша проверка должна включать контекст, можно просто показать командой, например, \frac
which является "допустимым правилом LaTeX" только при использовании в математическом режиме. Или что-то вроде \meter
which допустимо только в siunitx
командах .
Другой случай — expl3. Команды l3 также допустимы в LaTeX, если они заключены в \ExplSyntaxOn
и \ExplSyntaxOff
. Они будут построены примерно так:
cmd = "\" 1*(ALPHA | "_") ":" 0*ALPHA
что на самом деле не совсем так, поскольку символы после двоеточия ограничены, но этого должно быть достаточно.
А если вы захотите проверить действительность пользовательских макросов, ситуация станет еще хуже, \csname ...\endcsname
поскольку здесь у пользователя гораздо больше возможностей.
Обновлять:Самая интересная часть в конце концов будет также проверять, является ли вызов допустимым. Это будет означать, что вам придется проверить также сигнатуру функции, а затем вызов команды. Это будет означать, что он \frac
будет допустимым, только если он вызывается из математического режима и имеет два обязательных аргумента. Например, $\frac{1}{2}$
. Это тот момент, когда вы, вероятно, захотите скомпилировать образец документа, потому что настоящий парсер здесь будет очень сложным.
У всех этих методов есть одно предостережение: вы получите не только последовательности команд LaTeX, но и TeX. Если вы специально пытаетесь получить LaTeX, но хотите исключить TeX, у вас возникнут проблемы.
Обновление 2:Поскольку вас интересовала реализация для теста: Вот несколько регулярных выражений, которые вы можете использовать для сопоставления. Только при полном совпадении у вас будет действительная последовательность перед вами. Для контекстно-зависимой части вы можете захотеть работать с предпросмотрами и ретроспективными просмотрами.
- стандартный LaTeX:
\\[A-Za-z]*
- внутренний LaTeX:
\\[A-Za-z@]*
- синтаксис expl:
\\[A-za-z@_]*:[DNncVvoOxfTFpw]*
\csname
команды: что-то вроде\\.*$