在撰写有关编程语言或工具的文章时,人们经常希望在文档中包含它们的输出。如果可以在编译文档时创建此类输出,则很有用。例如,如果描述 Lua 函数,则可能希望在文档中显示该函数的返回值。在这种情况下,如果可以在编译文档时评估 Lua 函数,以便将返回值自动包含在文本中,则很有用。
另一种情况是,TeX 及其相关工具不适合创建或操作文档中所需的内容,这时就需要使用 TeX 及其相关工具的外部功能。例如,TeX 及其相关工具可能不适合分析数据。
这是使用其他编程语言和工具创建 TeX 文档内容的两个示例。如何有效地实施此类方法?
答案1
Org 模式
在Org 模式,这是 Emacs 的一种模式,你可以将文本与代码块的输出混合在一起许多不同的语言并将其全部导出到 LaTeX。可以在同一文档中使用不同的语言,也可以将一个代码块的输出发送到另一个代码块。这使得不同语言之间的交互成为可能。
这是一个非常简单的示例,其中显示了第一个代码块及其输出,第二个代码块使用第一个代码块的输出。在此示例中,代码块是用 Emacs Lisp 编写的。以下是 Org-mode 缓冲区的内容:
* Variable passing
** Example 1
In the following code the variable =foo= is set to the value bar. Since the function =setq= returns the last value it will return bar as shown below.
#+NAME: example-one
#+BEGIN_SRC emacs-lisp :exports both
(setq foo "bar")
#+END_SRC
** Example 2
In the following code the value of =foo= is set to the concatenation of the value of =x= and =x=. The value of =x= is set to the value returned in the example above (this happens in Org-mode).
#+NAME: example-two
#+BEGIN_SRC emacs-lisp :var x=example-one :exports both
(setq foo (concat x x))
#+END_SRC
按下 时,C-c C-e dOrg-mode 将导出到 LaTeX,对其进行编译并显示生成的文档。以下是 LaTeX 输出的一部分,请注意 Lisp 代码后面是其返回值:
\section{Variable passing}
\label{sec-1}
\subsection{Example 1}
\label{sec-1-1}
In the following code the variable \texttt{foo} is set to the value bar. Since the function \texttt{setq} returns the last value it will return bar as shown below.
\begin{verbatim}
(setq foo "bar")
\end{verbatim}
\begin{verbatim}
bar
\end{verbatim}
\subsection{Example 2}
\label{sec-1-2}
In the following code the value of \texttt{foo} is set to the concatenation of the value of \texttt{x} and \texttt{x}. The value of \texttt{x} is set to the value returned in the example above (this happens in Org-mode).
\begin{verbatim}
(setq foo (concat x x))
\end{verbatim}
\begin{verbatim}
barbar
\end{verbatim}
以下是最终文档的一部分:
这个例子非常简单,并没有展示这种方法的全部潜力。语言和工具之间可以进行更复杂的交互。以下两篇文章都是用 Org-mode 编写并导出到 LaTeX 的,它们展示了如何使用它来分析数据等的复杂示例:
用于文学编程和可重复研究的多语言计算环境。包含三个示例。第一个示例使用 Python 获取帕斯卡三角形的值,使用点绘制它并使用 Emacs Lisp 测试它是否正确。第二个是 C 的文学编程示例。第三个示例使用 shell 命令收集温度,使用 sqlite 创建数据库,使用 R 分析数据并绘制其图表。
使用 Org-Mode 激活文档。包含一个使用 shell 命令收集棒球数据、使用 Python、awk 和 R 分析数据并绘制图表的示例。本文的源代码位于https://raw.github.com/eschulte/CiSE/master/org-mode-active-doc.org。
答案2
腼腆
包裹bashful
专门用于在文档中包含命令行会话输出,因此可用于显示任何其他产生命令行输出的程序的输出。
引用用户手册:
...bashful 为 TEX 的原语提供了一个方便的接口
\write18
— 从输入文件中执行 shell 命令,也称为 shell escape。\bash
和之间的文本\END
由流行的 Unix 命令行解释器 bash 执行。 各种标志控制执行的命令及其输出是否显示在打印文档中,以及是否将它们保存到文件中。尽管已经规定可以使用 bash 以外的 shell,但是此软件包可能无法在 Microsoft 操作系统上不经修改而运行。
请注意,这需要-shell-escape
指定选项。
例子:
以下是使用基本命令的演示bash
。文档提供了更详细的示例。
bash 脚本文件的第一行以 开头%
,因此我从第 2 行开始列出清单,并将第一行留空。启动命令时,您需要为bash 文件和输出文件\bash
提供文件名。然后使用将该文件的内容重新合并到文件中。.sh
lstinputlisting
.tex
\documentclass{standalone}
\usepackage{xcolor}
\usepackage{bashful}
\usepackage{listings}
\lstdefinestyle{BashInputStyle}{
language=bash,
firstline=2,% Supress the first line that begins with `%`
basicstyle=\small\sffamily,
numbers=left,
numberstyle=\tiny,
numbersep=3pt,
frame=tb,
columns=fullflexible,
backgroundcolor=\color{yellow!20},
linewidth=0.9\linewidth,
xleftmargin=0.1\linewidth
}
\lstdefinestyle{BashOutputStyle}{
basicstyle=\small\ttfamily,
numbers=none,
frame=tblr,
columns=fullflexible,
backgroundcolor=\color{blue!10},
linewidth=0.9\linewidth,
xleftmargin=0.1\linewidth
}
\begin{document}
\bash[verbose,scriptFile=hello.sh,stdoutFile=hello.tex]
echo "Hello World!"
echo "Today is" `date`
echo ""
echo "Disk usage is:"
df
\END
\par\noindent
Executing the following code in \textbf{bash}
\lstinputlisting[style=BashInputStyle]{hello.sh}
%
yields the following output:
\lstinputlisting[style=BashOutputStyle]{hello.tex}
\end{document}
答案3
对于 ConTeXt,我编写了一个模块filter
可让您轻松调用外部程序并将结果包含回 TeX。与手动\write18
调用相比,此模块的主要功能包括:
- 它提供了一个很好的键值驱动语法。有关详细信息,请参阅 github 上的 README 文件。
- 它会缓存结果,并且只有当输入发生变化时才重新运行外部程序。
使用此模块,您可以使用任何外部程序来创建要包含在 TeX 中的内容。
例如,您可以使用过滤器模块并排显示程序的输入和输出。
\usemodule[filter,vim]
\definevimtyping[prettyRUBY][syntax=ruby]
\defineexternalfilter
[RUBY]
[
filter={ruby \externalfilterinputfile\space > \externalfilteroutputfile},
cache=yes, % Do not rerun the program if the file has not changed
readcommand=\TypesetAndPrint,
]
\def\TypesetAndPrint#1%
% The filter module expects #1 to be the
% file to read. But since we want to prettyprint
% the input as well, I ignore #1 and use
% `\externalfilterinputfile` and `\externalfilteroutputfile`
% instead
%
% A simple way to typeset the output is as follows
% {\typeprettyRUBYfile{\externalfilterinputfile}%
% \blank
% \typefile{\externalfilteroutputfile}}
% but we use a slightly more elaborate scheme and show the code
% and output side by side
{\startlinecorrection
\startcombination[2]
{\typeprettyRUBYfile{\externalfilterinputfile}}{Ruby program}
{\typefile{\externalfilteroutputfile}}{Output}
\stopcombination
\stoplinecorrection}
可以用作
\starttext
A ruby program
\startRUBY
puts "Hello World"
\stopRUBY
\stoptext
并给出
请注意,我正在使用该vim
模块来漂亮地打印源代码。可以使用相同的方法,例如在 markdown 中编写内容并使用 pandoc 将其转换为 TeX(参见此示例)或使用 R 生成图形(参见此示例)。
答案4
我读这个问题(标题)是使用其他语言来创建 TeX 文档,所以这个答案就是这样的。
该语言是 Ruby,库是克拉姆当这是一个用于解析和转换超集的库Markdown。它默认包含一个 LaTeX 转换器,但我想尝试制作一个适用于我自己的 TeX 格式(基本上是 plain-xetex 并带有一些附加功能)的转换器。
如果你看看LaTeX 转换器的来源,你会发现它是多么容易接近。至少我做到了,不像Pandoc 的,但这可能是因为我对 Ruby 比 Haskell 更熟悉。
在类内部,人们可以只用一种方法来处理转换,但是像在 LaTeX 转换器中一样,人们可以使用它来分派到特定元素类型的转换方法。
以下是 plain-xetex 列表元素的示例:
def convert_ul(el, opts)
opts[:level] = opts[:level].to_i.succ
retval = "\\smallskip\n" << inner(el, opts) << '\smallskip'
opts[:level] -= 1
return retval
end
alias :convert_ol :convert_ul
def convert_li(el, opts)
@ulmarks ||= %w(• ⬦ ‒)
type = "\\#{"item" * opts[:level]}"
case opts[:parent].type
when :ul : "#{type}{#{@ulmarks[opts[:level]-1]}} "
when :ol : "#{type}{#{opts[:index]+1}.} "
end << inner(el, opts)
end
是的,它并不完美;-)
,但它展示了开始转换并开始获得真实、切实的成果是多么容易!
但当我开始这样做时,我注意到一件有趣的事情,那就是我开始想知道 TeX代码我想在这个转换步骤上进行创建(例如,考虑脚注中的逐字记录,以及其他类似的\catcode
疯狂行为,或目录或引用等),以及我有多想将其作为 TeX 宏来做。这不是很明确(至少对我来说,目前是这样);一方面,人们可以走极端,只使用原语(我认为这会很酷),或者在另一个极端,为所有内容构建一个宏。这个认识对我来说真的很重要,因为它开辟了很多可能性。
制作一个 ConTeXt 转换器也相当酷。