新环境中的条件

新环境中的条件

我正在尝试创建一个环境,其中文本仅在可选参数未更改时出现(而当参数更改时消失)。我试图做的要点是:

\newenvironment{entry}[3][0]
    {\ifcase #1
    \textbf{#2} \hfill {\textit{#3}}\\
    \noindent
}
{\fi}

因此改变#1切换两个都 #2/#3 我在环境中实际输入的任何文本。如果我将文本放在\fi第一组括号内(在 之后\noindent),它会触发#2#3切换,但不会触发实际文本。但是,移至\fi第二组括号会出现“ifcase 不完整”错误。有没有办法稍微修改代码以产生我想要的效果?

我正在尝试创建一个稍微动态的文档,通过更改几个快速值,我可以让整个部分显示或不显示。如果您对如何更好地做到这一点有任何建议,请随时告诉我。

PS:如果有人可以向我推荐一个全面介绍条件句的资料来源,我将不胜感激。

答案1

怎么样

\documentclass{article}
\usepackage{environ}
\NewEnviron{entry}[3][0]{\ifnum#1=0
\textbf{#2} \hfill {\textit{#3}}\\
    \noindent\BODY\fi}
\begin{document}
\begin{entry}{a}{b}
Blub
\end{entry}

\begin{entry}[1]{c}{d}
Pft
\end{entry}
\end{document}  

答案2

分析

让我解释一下你的代码有什么问题。

当输入流中的下一个标记是条件时,TeX 会查找其后的适当测试,并决定是遵循真分支还是假分支。另一个分支将被跳过无需解释令牌,但要注意外层可能出现的条件,以便与正确的\else或相匹配\fi

条件\ifcase略有不同,请参见关于 \ifcase 语法的一个问题,但想法是完全一样的。

当你调用 时会发生什么\begin{entry}{Hello}{World}?没有可选参数,因此(跳过有关该过程的一些细节),TeX 最终会看到

\ifcase0 \textbf{Hello} \hfill {\textit{World}}\\\noindent<other text>\end{entry}

好的,测试告诉 TeX 仅在第一个\or\else,如果没有\or出现)之后跳过文本,因此它开始处理标记。到达 后\end{entry},TeX 会执行其常规工作,包括\endentry在本例中生成\fi。好!没有出现\or\else,因此没有什么可跳过的;\fi根据规则,标记会消失。

怎么办\begin{entry}[1]{Hello World}? 经过宏替换后,TeX 可以

\ifcase1 \textbf{Hello} \hfill {\textit{World}}\\\noindent<other text>\end{entry}<rest of the document>

这里的问题很明显:TeX 必须跳过文本,直到到达第一个\or\else\fi 在外层,因为它在跳过文本时不会进行宏扩展。并且所需形式的标记。TeX 将跳至文档末尾并抱怨条件不完整。

解决方案

在评估条件之前,您必须先吸收文本。标准方法是使用environxparse

后者更加强大并且更加友好。

\usepackage{xparse}

\NewDocumentEnvironment{entry}{O{0} m m +b}
 {\ifnum#1=0 \textbf{#2}\hfill\textit{#3}\\*#4\fi}
 {}

参数指定为

  • O{0}:可选参数,默认值为 0
  • m:标准强制参数
  • +b:环境主体,允许空行

“结束部分”是空的,因为那里没有特殊的处理要做。

这样,就\fi可以在外层看到。

与之environ几乎相同的是:

\usepackage{environ}

\NewEnviron{entry}[3][0]{%
 \ifnum#1=0 \textbf{#2}\hfill\textit{#3}\\*\BODY\fi
}

主要区别在于参数的语法与 for 相同,\newenvironment并且环境的主体由 表示\BODY

我推荐前者。 解决方案environ已在另一个答案中给出;请检查差异:

  1. \ifcase不是正确的使用条件;\ifnum更容易;
  2. \noindent是多余的;
  3. \\*将不允许在此特定换行符后进行分页。

答案3

例如,按照我的评论,您可以这样做:

\documentclass{article}

\newsavebox{\mybox}
\newenvironment{entry}[3][0]
    {%
    \def\mycase{0}%
    \def\myArg{#1}%
    \ifx\myArg\mycase
    \textbf{#2} \hfill {\textit{#3}}\\
    \else\relax\fi
    \savebox\mybox\bgroup\vbox\bgroup}
{\egroup\egroup\ifx\mycase\myArg\usebox{\mybox}\fi}


\begin{document}
Test

\begin{entry}{Some}{text}
My content will be shown
\end{entry}

\begin{entry}[2]{Some}{text}
My content will not be shown
\end{entry}
\end{document}

答案4

环境基本上(我不会告诉所有的细节和微妙之处)的工作原理如下:

\newenvironment{foo}[⟨args⟩][⟨optional⟩]%
               {⟨tokens before environment body⟩}%
               {⟨tokens after environment body⟩}
  • 定义了一个宏\foo,其定义的参数文本依据并且其定义的参数文本由 形成。[⟨args⟩][⟨optional⟩]⟨balanced text⟩⟨tokens before environment body⟩
  • \endfoo定义了一个不处理参数的宏,其定义⟨balanced text⟩由 组成⟨tokens after environment body⟩

使用\begin{foo)-macro \beginprocesses{foo}作为其参数,并且

  • 开始一个新的组/一个新的本地范围,
  • 重新定义\@currenvir扩展为当前环境的名称,即扩展为短语foo
  • 执行\csname foo\endcsname,即调用宏\foo,宏依次处理参数并在此传递⟨tokens before environment body⟩

使用\end{foo}-macro \endprocesses{foo}作为其参数,并且

  • 即调用\csname endfoo\endcsname宏,然后宏\endfoo又传递⟨tokens after environment body⟩
  • 检查的参数是否\end等于的展开\@currenvir,如果不相等,则传递错误消息,
  • 结束本地范围/本地组,
  • 在某些情况下会对环境之后出现的事物的间距做一些事情。

您的代码存在以下问题:

应该\fi匹配的\ifcase隐藏在宏的定义文本中,\endentry而控制字标记\endentry则要在执行 时构造\end{entry}
因此,当在处理\begin{entry}并由此扩展宏之后\entry,LaTeX 在标记流中搜索 的\ifcase匹配项时\fi,如果 -branch 中的条件\ifcase为假(= 如果可选参数表示大于 0 的数字),它肯定不会“看到”它,因此 -branch 中的内容\ifcase不会被扩展/执行。

我建议加载 verbatim-package,并在条件为假时使用其comment-environment 的内部结构。
这种方法的缺陷是您不能嵌套entry-environment。
这种方法的另一个缺陷是entry-ennvironment 不能在宏参数中或宏定义的平衡文本中使用,在这些地方,事物在类别代码机制下被标记,不适合entry通过 verbatim-package-code 吞噬 -ennvironment。
这种方法的另一个缺陷是,在包含 的行中\end{entry},短语\end{entry}后面不能有其他东西。同样值得一提的是,使用这种方法时,只有在环境主体被打印或不被视为注释的情况下,才会执行环境主体内的
全局分配(例如 - 之类的东西) 。\stepcounter

\documentclass{article}
\usepackage{verbatim}

\newenvironment{entry}[3][0]{%
    %\csname @\ifcase #1first\else second\fi oftwo\endcsname
    \csname @\ifnum#1=0 first\else second\fi oftwo\endcsname
    {%
      \textbf{#2} \hfill {\textit{#3}}%
      % \noindent right behind \\ has no effect as \\ 
      % does _not_ cause the starting of a new paragraph. (Only the first
      % line of a (new) paragraph would - without \noindent right _after_
      % starting the paragraph - horizontally be indented by
      %`\parindent`-glue.)
      \\*%
      \ignorespaces % This will make sure that a space(-token) right behind
                    % the closing brace of the environment's second 
                    % non-optional argument will not yield horizontal glue.
    }%
    {%
      \expandafter\let\csname end\csname @currenvir\endcsname\endcsname=\endcomment
      \comment
    }%
}%
{%
  % Due to (La)TeX's \endlinechar-mechanism line-endings in the source usually
  % are treated as if there were just spaces in the source. This in many 
  % situations leads to the coming into being of space-tokens. Space-tokens
  % in turn in might yield undesired horizontal glue in the .pdf-output.
  %
  %\ifhmode\unskip\fi % In case the last thing produced by (La)TeX was glue,
           % \unskip will remove that glue.
           % The above might remove horizontal glue which comes into 
           % being at the end of the last line of the environment's body due to
           % the \endlinechar-mechanism inserting a space at the end of lines.
           %
           % Instead you can end the last line of the environment-body with a
           % comment-char = a percent-char = %.
  \ignorespacesafterend % \ignorespacesafterend ensures that space-tokens
                        % behind \end{entry}, which might come into being due to the
                        % \endlinechar-mecnahnism, will not yield horizontal glue.
}

\newcounter{MyNiceDemoCounter}
\newcommand*\PrintMyNiceDemoCountersValue[1]{%
  \noindent
  \rlap{\lower-\ht\strutbox\hbox to\hsize{\hrulefill\null}}%
  #1 the environment the value of 
  {\csname verbatim@font\endcsname MyNiceDemoCounter}
  is \arabic{MyNiceDemoCounter}.\hfill\null
  \llap{\lower\dp\strutbox\hbox to\hsize{\hrulefill\null}}%
}%


\begin{document}

\PrintMyNiceDemoCountersValue{Before}\bigskip

X\begin{entry}{bold}{italic}
This environment is printed and 
\stepcounter{MyNiceDemoCounter}%
\verb|MyNiceDemoCounter| is stepped.
\end{entry}
X

\bigskip\PrintMyNiceDemoCountersValue{After}

\vfill

\PrintMyNiceDemoCountersValue{Before}\bigskip

X\begin{entry}[1]{bold}{italic}
This environment is not printed and 
\stepcounter{MyNiceDemoCounter}%
\verb|MyNiceDemoCounter| is not stepped.
\end{entry}
X

\bigskip\PrintMyNiceDemoCountersValue{After}

\vfill

\PrintMyNiceDemoCountersValue{Before}\bigskip

X\begin{entry}{bold}{italic}
This environment is printed and 
\stepcounter{MyNiceDemoCounter}%
\verb|MyNiceDemoCounter| is stepped.%
\end{entry}
X

\bigskip\PrintMyNiceDemoCountersValue{After}

\vfill

\PrintMyNiceDemoCountersValue{Before}\bigskip

X\begin{entry}[1]{bold}{italic}
This environment is not printed and 
\stepcounter{MyNiceDemoCounter}%
\verb|MyNiceDemoCounter| is not stepped.%
\end{entry}
X

\bigskip\PrintMyNiceDemoCountersValue{After}

\end{document}

在此处输入图片描述

相关内容