有时需要让输入的文字在页面上 逐字逐句原样出现:命令、注释和特殊字符的意义全部关闭,并用等宽(typewriter)字体输出。这种机制称为 verbatim。本页依次介绍行内的 \verb、块级 verbatim 环境、整文件输入的 \verbatiminput,以及“不能放在另一个命令参数中”这一重要限制和绕过方法;还会介绍保留少数命令有效的 alltt,以及可加行号和边框的 fancyvrb。
verbatim 环境与 \verb
逐字输出的基础是 LaTeX 自带的 verbatim 环境。写在 \begin{verbatim} 和 \end{verbatim} 之间的内容会按输入原样打印:反斜杠不再开始命令,而是作为 \ 输出;% 不再开始注释;空格和换行都原样保留;整个块用 typewriter 字体(\tt)排版。它适合展示程序源码,或包含许多 $、& 的符号串。
\begin{verbatim}
for i in range(3):
print("100% & $5") # nothing here is interpreted
\end{verbatim}只有一条必须遵守的规则:环境内部不能原样出现字符串 \end{verbatim}。LaTeX 一看到这个字符串,就会把它当作环境结束。如果确实需要显示 \end{verbatim} 这串文字本身,可用后面介绍的 fancyvrb 改变终止字符串,或用 \verb 单独处理这一段。
如果只想在一行 中间 插入一点逐字内容,使用行内形式 \verb。写法是:在 \verb 后面立刻放一个分隔字符,接着写要原样输出的文字,再用同一个分隔字符结束。分隔字符可以是 任意不出现在内容中的非字母字符。常见写法是 \verb|...|,但如果内容里有 |,就换成 \verb!...! 或 \verb+...+ 等。\verb 和分隔字符之间不能有空格。
The macro \verb|\textbf{...}| sets bold text, and
the pipe itself is shown with \verb!a|b! instead.带星号的 \verb* 会把内部空格打印成可见空格字符(␣),适合需要准确显示空格数量的代码例子。同样,verbatim* 环境也会把块内空格显示为 ␣。
不过,如果只是想处理容易包含 ~、#、%、_ 的字符串,例如 URL,那么 url 或 hyperref package 提供的 \url{...} 往往更方便,因为它还会在合适位置换行。
排版整个文件(\verbatiminput)
若要原样插入外部文件内容,verbatim package(属于 LaTeX required tools)提供的 \verbatiminput{filename} 很方便。先在导言区加载 \usepackage{verbatim},再在正文中写 \verbatiminput{program.py},该文件的每一行都会按 verbatim 排版。与手动复制进稿件不同,只要编辑源文件,输出会自动跟随更新,不必手动同步代码和文档。
\usepackage{verbatim}
% ...
\verbatiminput{hello.py}同一个 verbatim package 还会添加 comment 环境,它会跳过 \begin{comment} 到 \end{comment} 之间的所有内容。这不是用于逐字输出,而是用于 *完全不输出*,适合临时收起草稿段落。
不能放进命令参数中
这是 verbatim 最常见的绊脚点。\verb 和 verbatim 环境不能出现在另一个命令的参数中,例如 \section{\verb|code|}、\footnote{...}、表格单元格或 \caption{...} 内。原因在于 category code(catcode,即每个字符的角色)。\verb 会在读取参数前切换 catcode,但命令参数在命令被调用的那一刻 已经按通常 catcode 转换成 token list,因此在 \verb 来得及切换之前解释已经结束。这样写通常会报错。
有两个绕过方法。一个是 cprotect package:只要在需要保护的命令前加 \cprotect,其参数中的 verbatim 就能通过。例如写 \cprotect\section{\verb"foo"}。它还提供 \cprotEnv,用于保护环境的 \begin。
另一个是后面介绍的 fancyvrb 中的 \SaveVerb / \UseVerb:先把 verbatim 文本用一个名称保存起来,在命令参数中只调用这个名称。用 \SaveVerb{label}|verbatim text| 保存,用 \UseVerb{label} 输出。
% Workaround 1: cprotect
\usepackage{cprotect}
\cprotect\section{The \verb|\foo| command}
% Workaround 2: fancyvrb SaveVerb / UseVerb
\usepackage{fancyvrb}
\SaveVerb{cmd}|\foo|
\section{The \UseVerb{cmd} command}用 alltt 保留命令
在普通 verbatim 中,即使想给代码例子的 某一部分加粗或上色,也因为命令被关闭而无法做到。alltt package(也属于标准 LaTeX 发行版)及其 alltt 环境 可以解决这个问题。alltt 与 verbatim 类似,会用等宽字体按输入排版,但 反斜杠 \ 和花括号 {、} 保持通常含义。因此可以获得类似 verbatim 的外观,同时在内部使用 LaTeX 命令。
\usepackage{alltt}
% ...
\begin{alltt}
def \textbf{greet}(name):
return "Hi, " + name \textit{# a comment}
\end{alltt}在这个例子中,函数名 greet 变成粗体,注释部分变成斜体,其余内容都保持输入原样。代价是,如果想把 \、{、} 这三个字符 作为字符本身 输出,必须写成 \textbackslash、\{、\};而 verbatim 环境会直接输出它们。想手动加一点格式时用 alltt,想完全原样输出时用 verbatim。
用 fancyvrb 添加行号和边框
内建的 verbatim 不能添加行号或边框。功能更强的是 fancyvrb package,其核心是 大写 V 的 Verbatim 环境(不同于小写的 verbatim)。选项可以按环境指定,如 \begin{Verbatim}[key=value, ...],也可以在导言区用 \fvset{key=value, ...} 全局设置。
最常用的选项如下:numbers=left(或 right)添加行号,frame=single 给整个块画边框,fontsize=\small 指定字号。另外,commandchars 可以让本来是 verbatim 的文字内部仍有少数命令保持有效。
| 选项 | 常见值 | 作用 |
|---|---|---|
numbers | none / left / right | 行号位置(默认 none) |
frame | none / single / lines / leftline / topline / bottomline | 边框类型(默认 none) |
fontsize | \small、\footnotesize 等 | 字号(默认与正文相同) |
commandchars | 例如 \\\{\} | 指定 escape 字符与两个分组字符,从而启用命令 |
下面的例子是一个 Verbatim 块:左侧有行号,外面有单线边框,字体略小。
\usepackage{fancyvrb}
% ...
\begin{Verbatim}[numbers=left, frame=single, fontsize=\small]
def greet(name):
return "Hello, " + name
\end{Verbatim}指定 commandchars=\\\{\} 后,在 verbatim 文本内部,\、{、} 分别作为 escape 字符和分组分隔符使用,从而可以像 alltt 一样嵌入命令。还有用于读入整个文件的 \VerbatimInput[options]{filename};与 \verbatiminput 不同,它可以直接接受上面的选项。此外,通过前面介绍的 \SaveVerb / \UseVerb,verbatim 也能用于命令参数中。
最后提醒一点:这里介绍的机制只负责 原样输出,并不做给关键字上色之类的 语法高亮。如果要用颜色和格式展示程序源码,更合适的是专门的 listings package,或使用 Python Pygments 的 minted;这些内容在“代码清单”页面介绍。