我正在使用 MathQuill lib公式输入并尝试限制一些操作。有什么方法可以区分字符串和 LaTex 规则?
例如:
def check('\sum') => True #LaTex rule
def check('\myCustomVar') => False #NOT a LaTex rule
任何帮助将不胜感激!
答案1
至少在 Linux 上(不知道 Windows 上),有latexdef
Martin Scharrer 编写的脚本,它可以从命令行查找 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
这不是一个真正的答案,而是一个较长的评论。如果这些宏由核心包/类定义,Michael Palmer 给出的答案在大多数情况下都有效。
但是:您可能需要考虑某些情况。LaTeX 规则的制定方式可能意味着命令序列。典型的 LaTeX 命令序列(在以下示例中我将其称为“cmd”)可以生成为以下 ABNF:
cmd = "\" 1*ALPHA
但这还不够。您应该注意,您可能希望单独添加/排除一些内部宏。这意味着您必须检查类似
cmd = "\" 1*(ALPHA | "@")
对于内部宏。此类命令序列在使用时是否有效取决于上下文。虽然此规则会检查命令本身的有效性,但它大多必须在环境中使用才\makeatletter ... \makeatother
有效(如果您的检查应涉及上下文)。
并且您的检查应涉及上下文,这可以通过类似这样的命令简单地显示出来,\frac
即只有在数学模式下使用时才是“有效的 LaTeX 规则”。或者类似这样的命令仅在命令\meter
中有效。siunitx
另一种情况是 expl3。如果 l3 命令包含在\ExplSyntaxOn
和中,它们在 LaTeX 中也是有效的\ExplSyntaxOff
。它们将使用类似下面的代码构建:
cmd = "\" 1*(ALPHA | "_") ":" 0*ALPHA
这实际上并不完全正确,因为冒号后的字符受到限制,但这应该足够了。
如果您想检查用户定义的宏的有效性,情况会变得更糟,\csname ...\endcsname
因为用户在这里有更多选项。
更新:毕竟,最有趣的部分是还要检查调用是否有效。这意味着您还必须检查函数的签名,然后检查命令的调用。这意味着\frac
只有在从数学模式中调用并且具有两个强制参数时才有效。Fi 喜欢$\frac{1}{2}$
。这时您可能想要编译示例文档,因为真正的解析器在这里会非常复杂。
所有这些方法都有一个警告:您不仅会获得 LaTeX 命令序列,还会获得 TeX 命令序列。如果您特意尝试获取 LaTeX 命令序列,但又想排除 TeX 命令序列,那么您会遇到问题。
更新 2:正如您对测试的实现感兴趣:这里有一些您可以用来匹配的正则表达式。只有完全匹配时,您才会真正看到一个有效的序列。对于上下文相关的部分,您可能需要使用前瞻和后瞻。
- 标准 LaTeX:
\\[A-Za-z]*
- 内部 LaTeX:
\\[A-Za-z@]*
- expl 语法:
\\[A-za-z@_]*:[DNncVvoOxfTFpw]*
\csname
命令:类似于\\.*$