将任何乳胶代码作为参数的宏

将任何乳胶代码作为参数的宏

因此,我正在考虑创建一个以任何乳胶代码作为参数的宏。例如,

\newcommand\purp[1]{\color{purple} #1}

我希望这个宏能让 \purp 内的任何乳胶代码都变成紫色。但我意识到,如果我将某个环境(\begin.. \end)传递给参数,就会出现一些奇怪的乳胶错误。例如。

\purp{
\begin{verbatim} 
asdfadf
asdf
asdf
\end{verbatim}
}

破坏逐字输出并生成一堆乳胶错误。有没有安全的方法来创建一个以任意乳胶代码作为参数的函数?

编辑

除了逐字逐句之外,我还观察到以下内容产生了非常奇怪的错误。

\purp{
    \[
 x= \begin{cases*}
  y & if x_1 \text{ is } 1\\
  z & if x_2 \text{ is }  2
\end{cases*} 
\]
}

这会出现一个奇怪的错误:缺少 $ 插入。知道原因吗?

答案1

几乎通用的规则是verbatim材料不能作为命令的参数。使用该cprotect包,有时会出现如 MWE 中所示的解决方法,但即使这样也不是通用的解决方案。

编辑:添加组以防止紫色溢出到后续材料中(感谢 Ulrike)。

\documentclass{article}
\usepackage{cprotect,xcolor}
\newcommand\purp[1]{{\color{purple} #1}}
\begin{document}
\cprotect\purp{
\begin{verbatim} 
asdfadf
asdf
asdf
\end{verbatim}
}
\end{document}

在此处输入图片描述

答案2

如果只是关于颜色,你可以伪造一个\textcolor命令,它似乎接受一个参数,但确实支持逐字材料。请注意,这不是通用解决方案,而只是提供了一个参数,该参数采用的语法实际上\color并不是参数。

(这样,人们可以使用任何格式开关,而不仅仅是颜色,例如\bfseries也可以这样使用)

编辑:创建了一个\switchhack允许任意格式切换的功能,不仅是颜色,而且现在还\colorhack可以调用\switchhack

\documentclass[]{article}

\usepackage{xcolor}

\makeatletter
\begingroup\def\:#1{\endgroup\let\switchhack@sptoken= #1}\:{ }
\newcommand\switchhack[1]
  {%
    \def\switchhack@switch{#1}%
    \switchhack@a
  }
\newcommand\switchhack@a
  {%
    \futurelet\switchhack@gobbled\switchhack@b
  }
\newcommand\switchhack@b
  {%
    \ifx\switchhack@gobbled\switchhack@sptoken
      \switchhack@eatspace
    \fi
    \@firstofone
    {%
      \ifx\bgroup\switchhack@gobbled
      \else
        \GenericWarning
          {}{Warning: Argument of \string\switchhack\space not delimited}%
        \switchhack@undelimeted
      \fi
      \switchhack@delimited
    }%
  }
\long\def\switchhack@eatspace\fi#1#2%
  {%
    \fi
    \afterassignment\switchhack@a
    \let\switchhack@gobbled=
  }
\long\def\switchhack@undelimeted\fi#1#2%
  {%
    \fi
    {\switchhack@switch#2}%
  }
\newcommand\switchhack@delimited
  {%
    \afterassignment\switchhack@do
    \let\switchhack@gobbled
  }
\newcommand\switchhack@do
  {%
    \bgroup\switchhack@switch
  }
\long\def\colorhack#1#{\colorhack@{#1}}
\newcommand\colorhack@[2]
  {%
    \switchhack{\color#1{#2}}%
  }
\makeatother

\newcommand\purp{\colorhack{purple}}
\newcommand\bfhack{\switchhack{\bfseries}}

\begin{document}
\colorhack[rgb]{.5 .4 .8}{foo}
\purp{\verb|this is blue|}
following text
\bfhack{this is bold}

\colorhack{red} Undelimeted

\purp{
  \begin{verbatim}
  This is
  verbatim
  purple (I lied up there, it never was blue)
  \end{verbatim}
}
\end{document}

在此处输入图片描述

答案3

另一种获取以逐字材料为参数的宏的方法是将参数作为框来获取。同样,这不是通用的解决方案,您不能用它做任意的事情(最重要的是,在框化材料后,您无法更改其外观,这就是可选参数的用途grabbox,以使某些格式成为可能)。

下面定义了\purp将其参数放在 a 内部\hbox以及\purp*将其放在 a 内部\vbox(当然两种情况下的宏名都是\purp,第二个宏名后面只是加了一个星号)。

\documentclass[]{article}

\usepackage{grabbox}
\usepackage{xcolor}

\makeatletter
\newsavebox\purp@box
\newcommand\purp
  {%
    \begingroup
    \@ifstar
      {%
        \grabbox\purp@box[\color{purple}]\vbox{\unvbox\purp@box\endgroup}%
      }
      {%
        \grabbox\purp@box[\color{purple}]\hbox{\unhbox\purp@box\endgroup}%
      }%
  }
\makeatother

\begin{document}
\purp{\verb|this is blue|}

other text

\purp*{
  \begin{verbatim}
  This is
  verbatim
  purple (I lied up there, it never was blue)
  \end{verbatim}
}
\end{document}

在此处输入图片描述

相关内容