在简单的宏内排版代码?

在简单的宏内排版代码?

我想使用宏来排版具有通常特征的编程代码(特别是应该遵循行 - 这是最重要的问题;突出显示和类似的东西 - 目前 - 不打算使用)。这听起来很简单,但到目前为止我还没有成功。出于某种原因,类似这样的事情不起作用:

\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 生成四个标记asdf。此处,行尾字符位于包含空格以外内容的行上,因此生成了空格标记。

下一行是空白,因此行尾字符导致\par生成一个标记。下一行123与该行类似asdf。它生成 3其他标记123以及行尾字符导致产生空格标记。

综上所述,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它来排版。

相关内容