我正在为一篇课文写解决方案手册。有些解决方案只对讲师可见,所以我写了一个宏
\newcommand{\instructor}[1]{}
它隐藏了它的参数。我在学生版手册中使用了这个宏,而在教师版手册中使用了不同的定义。
使用 knitr 排版 R 代码时会出现问题。(knitr 是一个预处理器,它运行代码并将输出插入文本。)如果 R 代码包含百分号,knitr 会输出类似
\begin{knitrout}
\definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}
\begin{kframe}
\begin{alltt}
\hlnum{1} \hlopt{%%} \hlnum{2}
\end{alltt}
\end{kframe}
\end{knitrout}
(这表明1 %% 2
。)当它作为我的
\instructor
宏的参数出现时,百分号被视为注释标记,并且括号不匹配,从而导致错误。
所以,我的问题是:有没有一种方法可以做到这一点而不会失败?我猜它需要排版内容(因此 % 暂时转换为常规字符),然后丢弃输出。
编辑后补充:Ulrike 的解决方案适用于上述问题,但事情实际上更复杂,因为我有一些枚举,我想跳过学生版中的项目。例如,
\documentclass{article}
\begin{document}
% This pair of macros is what I'm using now, but the
% student version (the first one) fails.
% \newcommand{\instructor[#1]{\addtocounter{enumi}{1}}
\newcommand{\instructor}{}
\begin{enumerate}
\item This is for everyone:
\catcode`\%=11
{ 12 %% 13 }
\catcode`\%=5
\instructor{
\item This is just for the instructor:
\catcode`\%=11
{ 12 %% 13 }
\catcode`\%=5
}
\end{enumerate}
\end{document}
我不认为该comment
软件包提供了用完全不同的东西替换注释文本的解决方案,比如\addtocounter
。还是有?
答案1
不要使用带参数的命令——如果涉及到 catcode 更改,这将始终很困难。最好使用注释包:
\documentclass{article}
\usepackage{comment}
\includecomment{instructor}
%\excludecomment{instructor}
\begin{document}
bllb
\begin{instructor}
some text
\catcode`\%=11
12 %% 13
\catcode`\%=5
\begin{verbatim}
\section
\end{verbatim}
\end{instructor}
\end{document}
注意:来自文档的引用:
开始和结束命令应单独成行。起始命令和结束命令之间不应有任何空格,后面也不应有任何内容。
答案2
这不是一个很好的解决方案,但它确实有效。下面有一个更好但更复杂的解决方案。
将每次使用\instructor{}
包含文字%
字符的宏的\catcode
修改包装起来,例如在原始 knitr 代码中:
\catcode`\%=11
\instructor{
<<>>=
1 %% 2
@
}
\catcode`\%=5
TeX 向导可能知道如何将其构建到\instructor
宏定义中,但我不知道。
这适用于以下定义\instructor
:
% For the student version:
\newcommand{\instructor}[1]{}
% For the instructor version:
\newcommand{\instructor}{}
我仍然欣赏更优雅的解决方案!
编辑后添加:
根据 Ulrike 的回答,我认为我现在有一个相当优雅的解决方案。它使用该comment
包,并添加此宏定义:
\long\def\specialexclude
#1#2{\message{Excluding comment '#1'}%
\csarg\def{#1}{\endgroup \message{Excluding '#1' comment.}%
\begingroup%
\DefaultCutFileName #2\relax\def\ProcessCutFile{}%
\def\ThisComment####1{}\ProcessComment{#1}}%
\csarg\def{After#1Comment}{\CloseAndInputCutFile \endgroup}
\CommentEndDef{#1}}
这将添加一个新环境,并用任意命令替换其内容。你可以像这样使用它:
\documentclass{article}
\usepackage{comment}
\long\def\specialexclude
#1#2{\message{Excluding comment '#1'}%
\csarg\def{#1}{\endgroup \message{Excluding '#1' comment.}%
\begingroup%
\DefaultCutFileName #2\relax\def\ProcessCutFile{}%
\def\ThisComment####1{}\ProcessComment{#1}}%
\csarg\def{After#1Comment}{\CloseAndInputCutFile \endgroup}
\CommentEndDef{#1}}
% For the student version:
\excludecomment{instructor}
\specialexclude{instructori}{\addtocounter{enumi}{1}}
% For the instructor version:
% \includecomment{instructor}
% \includecomment{instructori}
\begin{document}
\begin{enumerate}
\item This is for everyone:
\catcode`\%=11
{ 12 %% 13 }
\catcode`\%=5
\begin{instructori}
\item This is just for the instructor:
\catcode`\%=11
{ 12 %% 13 }
\catcode`\%=5
\end{instructori}
\item This is also for everyone.
\end{enumerate}
\end{document}
答案3
将其分成两个标志可能更容易:一个用于 LaTeX,一个用于knitr
。将第三行更改为true
并将第一个块中的逻辑更改为TRUE
应该会计算出您想要的结果。
\documentclass{article}
\usepackage{ifthen}
\newcommand{\isinstructor}{false} %change to false/true
\newcommand{\instructor}[1]{\ifthenelse{\equal{\isinstructor}{true}}{#1}{}}
<<include = FALSE>>=
instructor <- FALSE #change to FALSE/TRUE
@
\begin{document}
Everyone sees this:
<<eval = FALSE>>=
1 %% 2
@
\instructor{Only the instructor can see this}
<<include = instructor>>=
1 %% 2 # 1 + 2 would be okay
@
\end{document}
包含的要求enumerate
也将按如下方式工作(请注意,讲师计数器减少以使其与前一个学生问题相同):
\documentclass{article}
\usepackage{ifthen}
\newcommand{\isinstructor}{false} %change to false/true
\newcommand{\instructor}[1]{\ifthenelse{\equal{\isinstructor}{true}}{\addtocounter{enumi}{-1} #1}{}}
<<include = FALSE>>=
instructor <- FALSE #change to FALSE/TRUE
@
\begin{document}
\begin{enumerate}
\item Everyone sees this:
<<eval = FALSE>>=
1 %% 2
@
\instructor{\item Only the instructor can see this}
<<include = instructor>>=
1 %% 2 # 1 + 2 would be okay
@
\end{enumerate}
\end{document}