我正在使用 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
這不是一個真正的答案,而是一個更長的評論。如果這些巨集是由核心包/類別定義的,那麼邁克爾·帕爾默給出的答案確實適用於大多數情況。
但是:您可能需要考慮某些情況。 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
只有在數學模式中調用它並且有兩個強制參數時才有效。菲喜歡$\frac{1}{2}$
。這就是您可能想要編譯範例文件的地方,因為真正的解析器在這裡會非常複雜。
所有這些方法都有一個警告:您不僅會獲得 LaTeX 命令序列,還會獲得 TeX 命令序列。如果您刻意嘗試取得 LaTeX 的但又想排除 TeX 的,則會遇到問題。
更新2:由於您對測試的實作感興趣:以下是一些可用於匹配的正規表示式。只有在完全匹配的情況下,您面前才會真正出現有效的序列。對於上下文相關的部分,您可能需要使用前瞻和後瞻。
- 標準乳膠:
\\[A-Za-z]*
- 內部乳膠:
\\[A-Za-z@]*
- 解釋語法:
\\[A-za-z@_]*:[DNncVvoOxfTFpw]*
\csname
命令:類似\\.*$