在不改变格式或间距的情况下将文本添加到文档

在不改变格式或间距的情况下将文本添加到文档

我是一名教师。当我出考试题时,我希望能够打印学生版的考试,然后打印考试答案。我的学生直接在考试卷上写答案,所以我留给他们写答案的空间通常足够大,可以容纳我想要的答案。问题是如何打印两个版本的考试。

请注意,我熟悉 EXAM 包(https://ctan.org/pkg/exam?lang=en),目前对使用它不感兴趣。查看其他答案,我认为我想要的是基于 smash 的东西(\smash 起什么作用?它的文档记录在哪里?)。

下面显示的是具有 \answerkey 的两个实现的 MWE。版本 A 是我尝试做我想做的事情——可选地包含答案,用红色表示,并将其粉碎,以便它不占用任何空间。不幸的是,对于下面的第一次使用,垂直间距在有答案和没有答案的情况下仍然会发生变化。对于下面的第二次使用,它完全中断,因为答案有多个段落。

最佳答案是单个 \answerkey 命令,它可以处理以下两种用途。目标是当使用 \answerstrue 或 \answersfalse 时文档的间距不会改变。

\documentclass[10pt]{article}

\usepackage{xcolor}
\usepackage{tikz}

\newif\ifanswers
\answerstrue
%\answersfalse

\newcommand{\answerkeyA}[1]{%
  \ifanswers%
   \textcolor{red}{\smash{\textbf{\parbox[t]{\linewidth}{#1}}}}%
  \fi%
}

\newcommand{\answerkeyB}[1]{%
  \ifanswers%
    #1%
  \fi%
}

\begin{document}

\begin{enumerate}
\item Answer the following question with words.

  \answerkeyA{ I do not like them in a house.  I do not like them with
    a mouse.  I do not like them here or there.  I do not like them
    anywhere.  I do not like green eggs and ham. }

  \vspace*{1in}
  
\item Draw a picture to illustrate the following problem.

\answerkeyB{
  Answer:

  \begin{tikzpicture}[scale=0.3,font=\sffamily]
    \draw [step=1.0, thin, gray!50] (-3, -3) grid (3, 3);
    \draw [arrows={latex-latex}] (-3,0) -- coordinate (x axis mid) (3,0);
    \draw [arrows={latex-latex}] (0,-3) -- coordinate (y axis mid) (0,3);
  \end{tikzpicture}
}

\vspace*{2in}

\item The next problem should be here.
\end{enumerate}

\end{document}

答案1

您可以执行\smash后跟\vspace,但\parbox有用于控制其高度和宽度的参数。

我会这样做,给出逻辑转换\ifanswers和为学生写答案的指定空间。

\newcommand\answer[2]{% #1 = size  #2 = answer
  \par \noindent
  \parbox[t][#1][s]{\linewidth}{%
     \ifanswers \color{red}#2\fi
     \par\vfill
  }\par
  \setlength\prevdepth{0pt}\medskip
}

[s]“拉伸”的参数和框\vfill末尾的 结合起来就像一个[t]参数,除了[t]当文本无法放入分配的空间时没有警告。当答案文本太大时,此版本会发出框满警告,答案可以打印在下一个问题上。

答案上方有一点额外的空间,这可能正是所需要的。(这是由于答案的顶部边缘位于“基线”处造成的。)此外,答案\medskip后面还有可选的额外空间以保持平衡。

再多做一些,\answer就可以将宏收紧,以便在问题和答案之间提供规则的基线间距。

\newcommand\answer[2]{% #1 = size  #2 = answer
  \par \noindent
  \parbox[t][#1][s]{\linewidth}{%
     % the next line preserves the top baseline alignment
     \vskip-\ht\strutbox \noindent\strut
     \ifanswers \color{red}\ignorespaces#2\fi
     \par\vfill
  }\par
  \setlength\prevdepth{0pt}%
}

在该版本中,段落在答案文本之前开始,并使用“支撑”加上否定将基线对齐到其所属的位置。允许\ignorespaces将答案写成

\answer{3cm}{
   this is the answer...
}

而不会引入虚假空间。

答案2

如果您希望间距不变,那么即使在学生版中您仍然需要对文本进行一些处理,以便 TeX 知道间距应该是多少。 \vphantom将留下适当的垂直间距,但也会中断段落。此解决方案是无论如何都要写答案,但要用隐形墨水(又名白色)。唯一的问题是 tikzpicture 还设置了颜色,因此我还需要一个新的颜色命令:\answercolor,它是您指定的颜色,或者是白色。(此外,\textcolor{white}{#1}也不喜欢段落分隔,所以我改用{\color{white}#1}。)(请注意,文本仍然存在,因此不适合以 pdf 形式提供 - 您可以复制并粘贴不可见的文本。但一旦打印出来,文本就不再存在了。

\documentclass[10pt]{article}

\usepackage{xcolor}
\usepackage{tikz}

\newif\ifanswers
%\answerstrue
\answersfalse

\newcommand{\answerkeyA}[1]{%
  \ifanswers%
   \textcolor{red}{\smash{\textbf{\parbox[t]{\linewidth}{#1}}}}%
  \else%
   \textcolor{white}{\smash{\textbf{\parbox[t]{\linewidth}{#1}}}}%
  \fi%
}

\newcommand{\answerkeyB}[1]{%
  \ifanswers%
    #1%
  \else%
   {\color{white}#1}%
  \fi%
}

\newcommand{\answercolor}[1]{%
 \ifanswers%
  #1%
 \else%
  white%
 \fi%
}

\begin{document}

\begin{enumerate}
\item Answer the following question with words.

  \answerkeyA{ I do not like them in a house.  I do not like them with
    a mouse.  I do not like them here or there.  I do not like them
    anywhere.  I do not like green eggs and ham. }

  \vspace*{1in}
  
\item Draw a picture to illustrate the following problem.

\answerkeyB{
  Answer:

  \begin{tikzpicture}[scale=0.3,font=\sffamily]
    \draw [step=1.0, thin, \answercolor{gray!50}] (-3, -3) grid (3, 3);
    \draw [arrows={latex-latex}] (-3,0) -- coordinate (x axis mid) (3,0);
    \draw [arrows={latex-latex}] (0,-3) -- coordinate (y axis mid) (0,3);
  \end{tikzpicture}
}

\vspace*{2in}

\item The next problem should be here.
\end{enumerate}

\end{document}

答案3

我想这可能就是你想要的。此解决方案提供了answer环境,你只需要将答案放入其中。你可以通过激活在教师/学生版本之间切换\answerfalse

教师版:

教师版

学生版:

学生版

关于此解决方案的更多详细信息:

  1. 我正在使用xparse来捕获环境主体answer。请注意,这需要较新版本的xparse。如果您无法访问它,请考虑改用environ包。
  2. 将内容放入可拆分文件tcolorbox中以测量高度。将内容放入输入流后,tcolorbox将负责将内容拆分到多个页面。
  3. 假设您不会改变\baselinestretch——如果行距发生变化,则可能需要修改计算。
  4. \answerfalse激活时,我将tcolorbox用高度等于原始内容的新行来填充。
  5. 因为环境的主体被捕获为参数,所以您将无法在里面使用逐字环境answer(例如align,,,等等)align*listing
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{amsmath, amssymb}
\usepackage{expl3}
\usepackage{xparse}
\usepackage{tikz}
\usepackage{blindtext}
\usepackage[breakable, skins]{tcolorbox}



\ExplSyntaxOn
\bool_new:N \g_show_answer_bool
\coffin_new:N \g_answer_coffin
\dim_new:N \g_answer_height_dim
\dim_new:N \g_answer_parbox_height_dim

% unit height of each \parbox for tcolorbox's
% page breaking algorithm to work with
\dim_gset:Nn \g_answer_parbox_height_dim {\baselineskip}

\newcommand{\answertrue}{\bool_gset_true:N \g_show_answer_bool}
\newcommand{\answerfalse}{\bool_gset_false:N \g_show_answer_bool}

% shows answer by default
\answertrue

\cs_set:Npn \my_tcbox:nn #1#2 {
    \begin{tcolorbox}[breakable, enhanced, left=0pt, right=0pt, top=0pt, bottom=0pt, boxsep=0pt, boxrule=0pt, colback=white, colframe=white, width=\linewidth, #2]
        #1
    \end{tcolorbox}
}

\cs_generate_variant:Nn \my_tcbox:nn {Vn}

\cs_set:Npn \my_height_box:n #1 {
    \exp_not:n{\parbox{\linewidth}{\rule{0pt}{#1}}}
}

% +b (body capture) requires `xparse` package to be no older than 2019-03-05 release
% or one can use environ package to achieve similar effects
\DeclareDocumentEnvironment{answer}{+b}{
    \bool_if:NTF \g_show_answer_bool {
        % shows answer
        \my_tcbox:nn {#1} {}
    } {
        % otherwise, use content that has identical height instead
        % put content in a minipage to measure height
        \hcoffin_gset:Nn \g_answer_coffin {
            \my_tcbox:nn {#1} {}
        }
        
        % get height of content
        \dim_gset:Nn \g_answer_height_dim {
            \coffin_dp:N \g_answer_coffin + 
            \coffin_ht:N \g_answer_coffin +
            \baselineskip
        }
        
        % check if height of content is longer than current page
        \fp_compare:nNnT {\g_answer_height_dim} > {\pagegoal - \pagetotal} {
            % if so, increase \g_answer_height_dim
            \dim_gadd:Nn \g_answer_height_dim {\baselineskip}
        }
        
        % compute how many units we need
        \fp_set:Nn \l_tmpa_fp {floor(\g_answer_height_dim / \g_answer_parbox_height_dim)}
        % create token list to fill vspace
        \tl_set:Nn \l_tmpa_tl {}
        \fp_step_inline:nnnn {1} {1} {\l_tmpa_fp} {
            \tl_put_right:Nn \l_tmpa_tl {\par\phantom{}}
        }
        % compute space less than \g_answer_parbox_height_dim
        \fp_set:Nn \l_tmpb_fp {\g_answer_height_dim - \l_tmpa_fp * \g_answer_parbox_height_dim}
        % fill remaining space
        \tl_put_right:Nx \l_tmpa_tl {\exp_not:N\vspace*{\fp_eval:n {\l_tmpb_fp} pt}}
        %\tl_show:N \l_tmpa_tl
        \my_tcbox:Vn \l_tmpa_tl {}
    }
}{}
\ExplSyntaxOff


% toggle version w/ or w/out answer
%\answerfalse

\begin{document}

\begin{enumerate}

\item Answer the following question with words.

\begin{answer}
I do not like them in a house.  I do not like them with a mouse.  
I do not like them here or there.  I do not like them anywhere.  
I do not like green eggs and ham.
\end{answer}

\item Draw a picture to illustrate the following problem.

\begin{answer}
\begin{tikzpicture}[scale=0.3,font=\sffamily]
    \draw [step=1.0, thin, gray!50] (-3, -3) grid (3, 3);
    \draw [arrows={latex-latex}] (-3,0) -- coordinate (x axis mid) (3,0);
    \draw [arrows={latex-latex}] (0,-3) -- coordinate (y axis mid) (0,3);
\end{tikzpicture}
\end{answer}

\item Write a long and useless article.

\begin{answer}
\Blindtext[4]
\end{answer}

\end{enumerate}


Space to top page top: \the\pagetotal


\end{document}

相关内容