我想使用宏来排版具有通常特征的编程代码(特别是应该遵循行 - 这是最重要的问题;突出显示和类似的东西 - 目前 - 不打算使用)。这听起来很简单,但到目前为止我还没有成功。出于某种原因,类似这样的事情不起作用:
\newcommand{\script}[1]{
\obeylines
#1
}
另一方面,逐字环境也不起作用 - 至少不是像这样(显然):
\newcommand{\script}[1]{
\begin{lstlisting}
#1
\end{lstlisting}
}
前段时间我发现了这个解决方案(我不太明白):
\makeatletter
\newcommand{\@skript}[1]{
\def\skript{%
{\bigbreak
\begin{minipage}{\textwidth}
\scriptsize\ttfamily{#1}
\end{minipage}
}
\par\noindent}
\skript
\egroup}
\newcommand\skript{\par\bgroup\obeylines\@skript}
\makeatother
它在原则上是可行的,但你不能围绕它构建任何东西,例如另一个宏或 ifthenelse 语句。
有什么好方法可以解决我的问题吗?
答案1
正如 Heiko Oberdiek 在评论中指出的那样,这里的问题是,当 TeX 扫描输入以读取宏参数时,它会对输入进行标记。如何执行此操作在电子书, 在TeX 按主题分类以及本网站。
粗略地说,这个过程由输入字符的类别代码控制,这些代码在输入被读取时有效。TeX 一次读取每一行输入,删除尾随空格并添加行尾字符。在标记化时,行尾字符可以是
- 被忽略(例如,如果该行以注释结尾或在控制字之后——即由像
\relax
或 这样的字母组成的控制序列\item
); - 转换为空格标记,如果行上有非空格输入,就会发生这种情况;或者
\par
如果该行仅包含空格,则转换为标记。
再次强调,完整详细信息请参阅其他地方。
因此,给定一个宏,例如\newcommand\foo[1]{#1}
,当 TeX 遇到
\foo{%
asdf
123
}
它需要确定参数是什么\foo
,因此它读取括号之间的所有输入并生成一系列标记。
包含的行\foo{%
以行结束符结束(所有行都是这样),但注释导致它被忽略,所以不会产生任何标记。
在下一行中\asdf
,前导空格被忽略(默认情况下总是如此),因此 TeX 生成四个信标记a
、s
、d
和f
。此处,行尾字符位于包含空格以外内容的行上,因此生成了空格标记。
下一行是空白,因此行尾字符导致\par
生成一个标记。下一行123
与该行类似asdf
。它生成 3其他标记1
、2
和3
以及行尾字符导致产生空格标记。
综上所述,TeX 处理这种情况的方式与以下代码相同:
\foo{asdf \par123 }
等到开始扩展时\foo
,已经没有任何“文本行”了。只有 10 个标记的序列。
这让我们想到了一个你不太理解的例子。让我尝试一个更简单的例子,希望它能更有意义。
\documentclass{article}
\newcommand*\skript{%
\par
\begingroup
\parindent=0pt
\obeylines
\obeyspaces
\skriptx
}
\newcommand\skriptx[1]{%
#1%
\par
\endgroup
}
\begin{document}
\skript{
Here's some text
that obeys lines and spaces
and it's part of the argument to a macro.
As you note, this cannot be used inside
another macro.
}
\end{document}
我定义了两个宏,\skript
和\skriptx
。第一个宏不接受任何参数。这一点至关重要,因为如上所述,参数在宏使用之前会被标记化。因此,会\skript
立即扩展为其替换文本。替换文本会结束任何当前段落,开始一个新组,将段落缩进设置为0pt
,指示 TeX 更改行尾字符和空格,最后扩展\skriptx
。
在遇到 时\skriptx
,其参数文本将根据当前有效的类别代码进行标记。由于\obeylines
和 是在 的参数被标记\obeyspaces
之前执行的\skriptx
,因此您可以在 的参数中获得所需的换行符\skriptx
。
结果如下所示。
但是真的没有办法告诉 Latex 简单地遵循宏参数中的行吗?
不是。你可以告诉 TeX 改变它处理行尾字符的方式前它已经将字符标记化了,但是一旦将其标记化,就太晚了。
其他“特殊”字符(如、、、_
和(以及其他几个))也是如此。^
%
#
希望现在清楚了为什么不能将类似\begin{lstlisting}
或的内容放入\verb
另一个宏中并期望它正确处理特殊字符(包括行尾字符)。
更详细地说,我要说的是通常排版代码不是问题。我建议将代码放在单独的文件中,然后使用\lstinputlisting
它来排版。