如何檢查字串是否是有效的 LaTex 規則?

如何檢查字串是否是有效的 LaTex 規則?

我正在使用 MathQuill lib公式輸入並試圖限制一些操作。有什麼辦法我可以區分字串和 LaTex 規則?

例如:

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

任何幫助將不勝感激!

答案1

至少在 Linux 上(不知道 Windows),有latexdefMartin 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命令:類似\\.*$

相關內容