我有一个包含一些问题及其解决方案的乳胶文档。我还有一个宏\excludecomment{sol}
,如果取消注释,则会排除解决方案环境。(对于环境也有类似的命令prob
。)
一般问题是我是否可以在这些宏中包含一个命令,或者以其他方式,以便根据宏是否处于活动状态来反映在 PDF 文件的文件名中(例如,在存在解决方案时在文件名中添加 _sol。)
答案1
您无法更改输出文件的名称/.pdf 文件的名称期间TeX 运行/LaTeX 运行。
原因是:
输出文件在 TeX 运行/LaTeX 运行开始时重新创建并打开以供写入。
(例如,在启动 tex 可执行文件或 latex 可执行文件后立即重新创建并打开以供写入。例如,在发送文档的第一页时重新创建并打开 .pdf 文件以供写入。)
输出文件(以及 .pdf 文件)保持打开以供写入,直到 TeX 运行/LaTeX 运行结束。
在大多数计算机平台上,您无法在文件打开以供写入时更改文件的名称。
但是在大多数 TeX 平台中,您可以使用命令行选项运行 tex 二进制文件/可执行文件。
其中一个选项是选项-jobname
。
如果你有主 .tex 文件foo.tex
并通过从命令行运行 latex 来编译它,如下所示
pdflatex --jobname=bar foo.tex
,您将不会获得输出文件foo.aux
、foo.log
和foo.pdf
等,但您将获得输出文件bar.aux
、bar.log
和bar.pdf
等。
同样,在这种情况下,原始人\jobname
不会传递短语foo
,但会传递短语bar
。
您不能在 LaTeX 运行期间使用宏来更改输出文件的名称,但您可以反其道而行之:
创建一个宏,检查的扩展是否\jobname
包含某些特定短语并相应地分叉。请注意,\jobname
会吐出类别代码 10(空格)的显式空格标记和类别代码 12(其他)的显式字符标记。
例子:
将以下示例保存为test.tex
:
\documentclass{article}
\usepackage{comment}
\begingroup
\makeatletter
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\long\def\UD@CheckWhetherNull#1{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
\@secondoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@firstoftwo}%
}%
%%----------------------------------------------------------------------
%% Check whether expansion of \jobname contains no phase "_sol"
%%......................................................................
%% \UD@CheckWhetherNoSolInJobname{<Tokens to be delivered in case that
%% \jobname contains no phrase "_sol">}%
%% {<Tokens to be delivered in case that
%% \jobname contains the phrsae "_sol">}%
\def\UD@GobbleToSol{_sol}%
\@onelevel@sanitize\UD@GobbleToSol
\edef\CheckWhetherNoSolInJobname{%
\noexpand\expandafter\noexpand\UD@CheckWhetherNull
\noexpand\expandafter{\noexpand\UD@GobbleToSol\jobname\UD@GobbleToSol}%
}%
\expandafter\long\expandafter\def
\expandafter\UD@GobbleToSol\expandafter#\expandafter1\UD@GobbleToSol{}%
\CheckWhetherNoSolInJobname{%
\endgroup
\newcommand\CheckWhetherNoSolInJobname[2]{#1}%
}{%
\endgroup
\newcommand\CheckWhetherNoSolInJobname[2]{#2}%
}%
%% \makeatother not needed. Instead the group is closed.
%%----------------------------------------------------------------------
\CheckWhetherNoSolInJobname{%
\excludecomment{sol}%
}{%
\includecomment{sol}%
}%
\begin{document}
Expansion of \verb|\jobname| is: \texttt{\jobname}
\texttt{\string\jobname} does
\CheckWhetherNoSolInJobname{%
not%
}{%
indeed%
}
contain the phrase \verb|_sol|.
Thus solutions
\CheckWhetherNoSolInJobname{%
are not included%
}{%
get included also%
}.
\bigskip
This is the question.
\begin{sol}
This is the answer.
\end{sol}
\end{document}
通过命令行进行编译,pdflatex test.tex
结果test.pdf
如下:
通过命令行进行编译,pdflatex --jobname=test_sol test.tex
结果test_sol.pdf
如下:
另一种方法可能是:
文件test_sol.tex
:
\newcommand\solutioninorexclude{%
\includecomment{sol}%
}%
\input test.tex
文件test.tex
:
\documentclass{article}
\usepackage{comment}
\providecommand\solutioninorexclude{%
\excludecomment{sol}%
}%
\solutioninorexclude
\begin{document}
This is the question.
\begin{sol}
This is the answer.
\end{sol}
\end{document}
编译test_sol.tex
结果test_sol.pdf
:
编译test.tex
结果test.pdf
:
此方法的另一种变体是,如果文件不存在,则自动为您test.tex
创建该文件:test_sol.tex
当您将下面的示例另存为test.tex
并编译它时,您将获得一个test.pdf
包含文本但不包含解决方案的文件。您还会获得一个文件test_sol.tex
。如果您编译它,它将通过\input
—importtest.tex
以包含环境的方式进行。因此,您将获得一个也包含解决方案的sol
文件:test_sol.pdf
\documentclass{article}
\usepackage{comment}
\providecommand\solutioninorexclude{%
\excludecomment{sol}%
\includecomment{solinputfile}%
}%
\solutioninorexclude
\begin{solinputfile}
\begingroup
\makeatletter
\IfFileExists{\jobname\string_sol.tex}{%
\@latex@warning@no@line{File \jobname\string_sol.tex already exists. Not generating it}%
}{%
\@latex@warning@no@line{Generating file \jobname\string_sol.tex}%
\newwrite\solinputfile
\immediate\openout\solinputfile\jobname\string_sol.tex\relax
\immediate\write\solinputfile{%
\string\newcommand\string\solutioninorexclude{\@percentchar^^J%
\space\space\string\includecomment{sol}\@percentchar^^J%
\space\space\string\excludecomment{solinputfile}\@percentchar^^J%
}\@percentchar^^J%
\string\input\space\jobname.tex%
}%
\immediate\closeout\solinputfile
}%
\endgroup
\end{solinputfile}
\begin{document}
This is the question.
\begin{sol}
This is the answer.
\end{sol}
\end{document}
另一种方法可能是使用类似文档条 包。目的是文档条 软件包正在复制 tex-source-code 文件并删除注释。它提供了将代码有条件地包含到副本中的方法。
例如,如果您将以下示例保存为test.tex
并进行编译,那么您不会获得 .pdf 文件,但会获得两个新的文本文件。
%<*ignore>
\input docstrip
\nopreamble
\nopostamble
\askforoverwritetrue
\generate{\file{\jobname\string_sol.tex}{\from{\jobname.tex}{sol}}}
\generate{\file{\jobname\string_nosol.tex}{\from{\jobname.tex}{}}}
% Here you can do some \immediate\write18-calls for calling LaTeX or
% TeXify or latexmk for compiling \jobname_sol.tex and
%\jobname_nosol.tex.
% You need to have the \write18-feature enabled for this.
% Some people take enabling \write18 for a security issue.
\csname stop\endcsname
\bye
%</ignore>
\documentclass{article}
% This comment won't occur in the generated files.
% This comment won't occur in the generated files.
\begin{document}
This is the question.
%<*sol>
This is the answer.
%</sol>
\end{document}
其中一个文本文件被命名test_nosol.tex
,其内容为:
\documentclass{article}
\begin{document}
This is the question.
\end{document}
其中另一个文本文件的名称test_sol.tex
及其内容为:
\documentclass{article}
\begin{document}
This is the question.
This is the answer.
\end{document}
答案2
我也遇到过同样的情况多年今天浏览 TeX.stackexchange 后,我找到了以下解决方案。它并没有严格回答您的问题,但我发现它很容易用作解决方法。我使用包,exam
但这应该适用于任何可以选择使用宏注释掉某些部分的包。对于exam
包,可选包含的代码在环境中solution
。我创建了三个文件,其方案如下(但实际上名称更短):
1)main_questions_only.tex,其全部内容为
\documentclass[11pt]{exam}
\noprintanswers
\input{main.tex}
2)main_questions_with_solutions.tex,其全部内容为
\documentclass[11pt]{exam}
\printanswers
\input{main.tex}
3)main.tex 包含其他所有内容。
答案3
本质上这个问题是TeX 可以对其生成的 PDF 进行后期处理吗?。
LuaTeX 有一个回调可以用于此。
%! TEX program = lualatex
\documentclass{article}
\usepackage{luacode}
\begin{document}
123
\begin{luacode*}
luatexbase.add_to_callback("wrapup_run", function()
local outfile=io.open(tex.jobname.."_sol.pdf", "wb")
outfile:write(io.open(tex.jobname..".pdf", "rb"):read("a"))
outfile:close()
os.remove(tex.jobname..".pdf")
end, "final callback to rename pdf file")
\end{luacode*}
\end{document}
请注意,文档(texdoc luatex)指出......
需要您自担风险使用它。
因此,如果您使用此解决方案,请准备好调试新编译器版本中可能出现的任何问题。