“激活”作为宏传递的参数中的活动字符

“激活”作为宏传递的参数中的活动字符

假设我有一些宏(\iPrint在 MWE 中),它在内部使用活动字符来解释其参数:

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\begingroup
  \lccode`\~=`\|
  \lowercase{\endgroup
    \def~#1~{\textbf{#1}}%
  }
\def\iPrint{%
  \begingroup
  \catcode`\|=\active
  \iPrintX
}
\def\iPrintX#1{%
  #1
  \endgroup
}

\begin{document}
\def\temp{This |doesn't work|, though :-(}
\begin{itemize}
  \item \iPrint{This |works pretty| well!}
  \item \iPrint{\temp}
\end{itemize}
\end{document}

得出:

输出

据我所知,问题是,catcode 是在宏定义时分配的:\temp定义时,|不处于活动状态。但是,我是否可以在其中执行一些操作\iPrint以使其处于活动状态?使用当前 catcode 对参数进行某种重新编码?

答案1

当你说

\def\temp{This |doesn't work|, though :-(}

的类别代码|是固定的,\catcode`|=\active在进行扩展时设置不起作用\temp|替换文本中的字符具有类别代码 12。

可以用来\scantokens重新分配类别代码,但必须扩展宏 \scantokens发挥作用:

\makeatletter
\begingroup
  \lccode`\~=`\|
  \lowercase{\endgroup
    \def~#1~{\textbf{#1}}%
  }
\def\iPrint#1{%
  \begingroup
  \catcode`\|=\active
  \protected@edef\reserved@iprint{\noexpand\scantokens{#1\noexpand\empty}}\reserved@iprint
  \endgroup
}
\makeatother

如果已知输入\iPrint仅为文本或宏(例如\iPrint{\temp}),那么更简单的

\def\iPrint#1{%
  \begingroup
  \catcode`\|=\active
  \scantokens\expandafter{#1\empty}%
  \endgroup}

可以工作。如果参数更复杂(文本和宏),则\protected@edef似乎需要更复杂的方法;它将扩展所有宏,但不会深入研究“受保护”的宏。

\empty参数末尾的是\scantokens惯例,以避免出现虚假空格:\scantokens实际上模拟文件的输入,并且所有文件都隐式以空行结束。\protected@edef它里面不能扩展,所以我们\noexpand在它前面添加。

(感谢 Bruno Le Floch 纠正错误。)

答案2

当读取输入字符时,会分配 catcode。TeX 随后会查找此输入的当前值并附加 catcode。之后无法更改。因此,如果要更改输入,必须重新读取输入。例如,将其写入文件,然后重新输入此文件。或者使用\scantokens

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\begingroup
  \lccode`\~=`\|
  \lowercase{\endgroup
    \def~#1~{\textbf{#1}}%
  }
\def\iPrint{%
  \begingroup
  \catcode`\|=\active
  \iPrintX
}
\def\iPrintX#1{%
  #1
  \endgroup
}

\begin{document}
\def\temp{This |doesn't work|, though :-(\relax}
\begin{itemize}
  \item \iPrint{This |works pretty| well!}
  \item \iPrint{\scantokens\expandafter{\temp}}.
  \item \iPrint{\temp}.
\end{itemize}
\end{document}

相关内容