将 TeX 显示数学样式 ($$ MATH $$) 转换为 LaTeX (\begin{equation*} MATH \end{equation*})

将 TeX 显示数学样式 ($$ MATH $$) 转换为 LaTeX (\begin{equation*} MATH \end{equation*})

我正在尝试编写一个脚本(在emacs lisp)来转换TeX显示数学样式,例如,

$$
x + y = z
$$

进入LaTeX

\begin{equation*}
x + y = z
\end{equation*}

为了达到我的目的我设想了这个算法:

  1. 在扫描文件中的"$$"字符串时,我会一次又一次地临时替换字符串,"$$"如下"$$\TESTIFDISPLAYMATH"所示\TESTIFDISPLAYMATH

    \newcommand{\TESTIFDISPLAYMATH}{\mathchoice{\wlog{DISPLAY MATH OK}}{}{}{}}
    

    (这是必要的,以避免出现“$x,$$y,$”之类的误报)

  2. 此时,我将编译我的.tex文件以生成.log文件并扫描它以查找我的目标字符串。

  3. 删除"\TESTIFDISPLAYMATH"字符串后,如果“DISPLAY MATH OK”,我将执行替换。

我的问题是:

  1. 我能否以更快的方式完成任务?我的意思是,例如,无需.tex为每个实例完全编译我的文件"$$"

  2. 有没有可以做到这一点的工具?

我愿意接受任何建议。

答案1

我确实不知道最好的方法是什么,但这里有几个建议。

  1. 由于您使用的是 Emacs,因此您可以尝试以下正则表达式替换:

    \$\$\([^$]+\)\$\$ → \\begin{equation}\1\\end{equation}
    

    这将匹配任何形式的$$…$$,其中可以是任何不包含 的字符序列(包括换行符)$。它不会因您提到的误报而失败($x,$$y,$),但会因类似 的内容而失败$x,$$y,$$z,$

    为了安全起见,您可能希望先\\用一些独特的东西替换,然后再用\$一些独特的东西替换(两者都不是正则表达式),然后撤消这些替换。第一次替换是为了防止替换\$in \\$,第二次替换是为了防止替换\$$when\$是文字 $ 符号,第二次替换开始或结束一个等式。

  2. 如果你想知道所有显示数学环境的行号,你可以添加

    \everydisplay\expandafter{\the\everydisplay\GenericWarning{\relax}{DISPLAY MATH}}
    

    到你的序言。这将打印DISPLAY MATH on input line <line>每个显示方程。

    ( 的内容\everydisplay插入到每个显示环境的开始处。您可以使用 向其中添加一些内容\everydisplay\expandafter{\the\everydisplay<addition>}。 )

  3. 您的\TESTIFDISPLAYMATH算法实际上不起作用,因为 的每个分支\mathchoice始终都会执行(尽管只打印一个)。因此,DISPLAY MATH OK无论是否从显示环境中调用此宏, 都会打印。

    如果你想走这条路,你可能想尝试类似

    \let\TESTIFDISPLAYMATH\empty %% <- does nothing
    \makeatletter %% <- make @ usable in command names
    \everydisplay\expandafter{\the\everydisplay
      \@ifnextchar\TESTIFDISPLAYMATH{\wlog{DISPLAY MATH OK}}{}}
    \makeatother  %% <- revert @
    

    你应该添加这个在最后你的序言(特别是在加载之后amsmath,或者甚至可能在加载之后\begin{document}(为了安全起见)。DISPLAY MATH OK只要等式中出现的第一件事是,它就会打印\TESTIFDISPLAYMATH。它可能与某些包不兼容(如果它们\everydisplay在运行时发生变化,但我不知道有任何变化)。

    或者你可以尝试

    \let\TESTIFDISPLAYMATH\empty %% <- does nothing
    \everydisplay\expandafter{\the\everydisplay
      \renewcommand\TESTIFDISPLAYMATH{\wlog{DISPLAY MATH OK}}}
    

    这种方式\TESTIFDISPLAYMATH通常不执行任何操作,但它被重新定义为DISPLAY MATH OK在显示数学环境中使用时写入日志文件。不过,在这样的环境中使用时也会触发\text{…},因此它仍然不完美。

答案2

虽然没有经过严格测试,但 Lisp 函数看起来可能像这样。它$$用环境替换所有出现在一行中的equation*。如果使用 调用C-u M-x,它还会查找 inline$$并替换它们。

(defun GN/fix-math ()
  "Search and replace TeX's $$ with LaTeX's \"equation*\" environment.
Replaces only $$ in single lines.  If invoked with `C-u', then
also looks after $$ which are inline.  User is asked for
confirmation then."
  (interactive)
  (save-excursion
    (save-restriction
      (widen)          
      (goto-char (point-min))
      (let ((kill-whole-line nil))
        (while (and (re-search-forward (concat "^[ \t]*" (regexp-quote "$$") "[ \t]*$") nil t)
                    (texmathp))
          (beginning-of-line)
          (kill-line)
          (insert "\\begin{equation*}")
          (re-search-forward (concat "^[ \t]*" (regexp-quote "$$") "[ \t]*$") nil t)
          (beginning-of-line)
          (kill-line)
          (LaTeX-close-environment)
          (forward-line -1)
          (LaTeX-fill-environment nil)))))
  (when current-prefix-arg
    (save-excursion
      (save-restriction
        (widen)
        (goto-char (point-min))
        (while (re-search-forward (regexp-quote "$$") nil t)
          (when (yes-or-no-p "Replace $$? ")
            (delete-char -2)
            (newline)
            (save-excursion
              (end-of-line -1)
              (delete-horizontal-space))
            (insert "\\begin{equation*}")
            (newline)
            (indent-according-to-mode)
            (re-search-forward (regexp-quote "$$") nil t)
            (delete-char -2)
            (LaTeX-close-environment)
            (forward-line -1)
            (LaTeX-fill-environment nil)))))))

相关内容