我想写一篇数学论文,其中既有公式,也有程序片段,并排显示。但是我不希望 TeX 显示或记录程序,只是希望能够将它们提取到文件中(如果需要)。
请注意,我的意图与文字编程无关,但也许我可以(错误地)使用其中一些工具来达到我的目的?例如,假设预解析器有一个特殊的标记 %#,这样的文件可能如下所示:
\documentclass[]{article}
\begin{document}
The factorial is an important function:
\begin{equation}
n! = \prod_{k=1}^n k
\end{equation}
%# n := 1;
%# for k from 1 to n
%# n := n * k;
\end{document}
我的问题是:是否有工具(或编辑器)可以预解析 TeX 文档并将其拆分为两个(或更多)不同的文件,以便由不同的工具进一步处理?或者还有其他使用 TeX 功能的想法?
编辑:作为对 jfbu 优秀答案的扩展:假设代码片段紧跟在编号方程之后,我们是否也可以将方程的编号写出到代码文件中?这将相当于两个输出之间的交叉引用。(如果这不可能,那么如何写出 jfbu 的“详细答案”中引入的内部片段计数器(带有前置注释符号,如 # 或 // ?)。
答案1
您可以从 tex 内部执行此操作,无需外部工具。
此更新为每个代码片段生成一个文件,并自动(可自定义)编号。此示例生成filename-code-01.py
、filename-code-02.py
、filename-code-03.py
,filename-code-04.py
对应于四个代码片段(两个在序言中)。
针对 OP 的编辑做出的补充更新:现在,每个输出代码片段的第一行都是带有代码片段编号的注释行。关于使用公式编号的问题更加微妙,因为代码片段的提取是作为前言代码的一部分进行的,在文档中实际排版任何内容之前。
$ ls preparseC*
preparseC-code-01.py preparseC-code-04.py preparseC.log
preparseC-code-02.py preparseC.aux preparseC.tex
preparseC-code-03.py preparseC.dvi
内容preparseC-code-01.py
:
# Code snippet 1
n := 1;
for k from 1 to n
n := n * k;
用于标识.tex
源文件中的代码片段的行标记是%#<space><space>
。
代码:
\documentclass{article}
\newcounter{snippetno}
% customize \thesnippetno as desired, for example this produces
% filename-code-01.py
% filename-code-02.py
% ...
% filename-code-10.py
% etc...
% This command should be expandable
\renewcommand{\thesnippetno}
{\jobname-code-\ifnum\value{snippetno}<10 %<- leave a space
0\fi
\arabic{snippetno}.py}
%%%%%%%% PREPARSING
\newread\parsein
\openin\parsein \jobname.tex
\newwrite\parseout
% this version will create one file for each code snippet
\newif\ifOutputtingLines
% adapt the following to the line tag you want to use
% the \detokenize is not needed here, but in case your tag
% uses letters, put them in it (do not use \catcode for letters
% a they may be in use in \def \endgroup etc..)
%
% THIS VERSION USES %#<space><space> AS LINE TAG
% (two spaces must be present and will be removed in the outputs)
\begingroup
%% ADDED DEFINITION OF \COMMENTTAG FOR USE IN FIRST LINE OF CODE SNIPPET FILES
\catcode`\% 12
\catcode`\# 12
\def\x{\endgroup\def\COMMENTTAG{#}\edef\LineTag{\detokenize{%#}\space\space}}
\x
%\show\LineTag % debugging
\begingroup
\edef\x{\endgroup
\unexpanded{\def\CheckLineAux #1}\LineTag\relax \unexpanded{{#1}}
\unexpanded{\def\CheckLine #1}\LineTag \unexpanded{#2}\relax
\unexpanded{{\if\relax #1\relax
\ifOutputtingLines\else
\stepcounter{snippetno}%
\immediate\openout\parseout \thesnippetno\relax
%% ------------------------ ADDED TO INSERT CODE SNIPPET NUMBER IN THE FILE
\immediate\write\parseout
{\COMMENTTAG\space Code snippet \arabic{snippetno}}%
%% ------------------------
\OutputtingLinestrue
\fi
\immediate\write\parseout {\CheckLineAux #2\relax}%
\else
\ifOutputtingLines
\immediate\closeout\parseout
\OutputtingLinesfalse
\fi
\fi}}%
}
\x
\begingroup\endlinechar-1
\loop
\ifeof\parsein
% if \end{document} is not missing no need to \closeout\parseout
% necessarily already done, and OutputtingLines toggle necessarily false
\closein\parsein
\else
\readline\parsein to \tmpline
\if\relax\tmpline\relax % found empty line
\ifOutputtingLines\immediate\closeout\parseout
\OutputtingLinesfalse
\fi
\else
\expandafter\expandafter\expandafter \CheckLine
\expandafter \tmpline\LineTag \relax
\fi
\repeat
\endgroup
%%%%%%%% END OF PREPARSING
% Some code snippets may already be put here in the preamble
%
%# n := 1;
%# for k from 1 to n
%# n := n * k;
%# y := 1;
%# for k from 1 to n
%# y := y * (x + k -1);
% Notice that in this variant the line tag is %#<space><space>
% and is removed on output
\begin{document}
The factorial is an important function:
\[
n! = \prod_{k=1}^n k
\]
%# n := 1;
%# for k from 1 to n
%# n := n * k;
The (so-called) Pochhammer coefficient also:
\[
(x)_n = \prod_{k=1}^n (x+k-1)
\]
%# y := 1;
%# for k from 1 to n
%# y := y * (x + k -1);
\end{document}
这是答案的第一个版本:(我删除了\makeatletter
没用的部分,并注释掉了\show\LineTag
调试行)
以下内容将在编译时提取到filename-code
标记的行。
n := 1;
for k from 1 to n
n := n * k;
代码:
\documentclass{article}
%%%%%%%% PREPARSING
\newread\parsein
\openin\parsein \jobname.tex
\newwrite\parseout
\immediate\openout\parseout \jobname-code
% adapt the following to the line tag you want to use
% the \detokenize is not needed here, but in case your tag
% uses letters, put them in it (do not use \catcode for letters
% a they may be in use in \def \endgroup etc..)
\begingroup
\catcode`\% 12
\catcode`\# 12
\def\x{\endgroup\edef\LineTag{\detokenize{%#}}}
\x
%\show\LineTag % debugging
\begingroup
\edef\x{\endgroup
\unexpanded{\def\CheckLineAux #1}\LineTag\relax \unexpanded{{#1}}
\unexpanded{\def\CheckLine #1}\LineTag \unexpanded{#2}\relax
\unexpanded{{\if\relax #1\relax
\immediate\write\parseout {\CheckLineAux #2\relax}%
\fi}}%
}
\x
\begingroup\endlinechar-1
\loop
\ifeof\parsein
\immediate\closeout\parseout
\closein\parsein
\else
\readline\parsein to \tmpline
\if\relax\tmpline\relax\else
\expandafter\expandafter\expandafter \CheckLine
\expandafter \tmpline\LineTag \relax
\fi
\repeat
\endgroup
%%%%%%%% END OF PREPARSING
\begin{document}
The factorial is an important function:
\[
n! = \prod_{k=1}^n k
\]
%# n := 1;
%# for k from 1 to n
%# n := n * k;
\end{document}
答案2
还有更多更广泛的工具,但如果你保存了你的例子,fff.tex
那么grep
这sed
就是你所需要的
grep -v "^%#" fff.tex
生产
\documentclass[]{article}
\begin{document}
The factorial is an important function:
\[
n! = \prod_{k=1}^n k
\]
\end{document}
和
grep "^%#" fff.tex | sed "s/^%#//"
生产
n := 1;
for k from 1 to n
n := n * k;
答案3
grep
它也可以通过一个简单的 perl 脚本来完成,对我来说,它比sed
带有选项的脚本更具可读性。
#!/usr/bin/perl
while(<STDIN>)
{
if( (substr $_, 0, 2) eq "%#" )
{
print substr $_, 2;
}
}
文档保存在 中document.tex
,perl 代码保存在 中extractComments.pl
。
生成:
hpek@melda:~/programming/perl$ cat document.tex |./extractComments.pl
n := 1;
for k from 1 to n
n := n * k;
hpek@melda:~/programming/perl$
答案4
我的想法:如果你的代码块是 R(http://www.r-project.org/),我会考虑knitr
,http://yihui.name/knitr/(或者现在更老的斯维夫,http://www.stat.uni-muenchen.de/~leisch/Sweave/)。
如果不是,我会尝试这个extract
包,http://ctan.org/pkg/extract,如果它符合您的需求。
就我个人而言,我可能会选择listings
套餐,http://mirrors.nic.cz/tex-archive/macros/latex/contrib/listings/listings.pdf,代码可以立即排版,并且如果需要,我们可以打开/关闭它的环境(然后它们将表现为注释),即时提取它们,并且我们可以同时让主 TeX 文件内外的代码块被其他程序编译。