需要条件,其结果为无

需要条件,其结果为无

解决:问题出在moderncv我使用的版本太旧了。我在问题的末尾添加了一些额外的细节,但我将删除这个问题。感谢那些写信澄清\ifx工作原理的人。如果我能更好地理解这一点,我就会马上意识到这个问题。


我有一些使用包的代码。该包提供了一些具有可选参数的命令。我为这些参数提供了一些文本,但我希望能够编译我的文档的替代版本,其中隐藏了该文本。

因此,我尝试定义某种布尔标志,当它设置为 true 时,结果就像这些参数为空一样。不幸的是,我尝试过的所有方法似乎都无法实现这一点。

我将在下面附上一个 MWE,说明我尝试过的几种方法,并说明为什么结果不令人满意。我不知道还能尝试什么,所以任何帮助都将不胜感激!

\documentclass{article}

\usepackage{etoolbox}

% I want a flag that, if true, will cause certain strings to be hidden, as if
% they were not in the document at all.  Below I try a couple ways of defining
% such a flag.
\newif\ifhidestuff
    \hidestufftrue
%   \hidestufffalse
    
\newtoggle{hidestuff}
    \toggletrue{hidestuff}
%   \togglefalse{hidestuff}
    
% Below is an example of a command that behaves differently according as one
% of its arguments is empty
\newcommand{\withoptarg}[2]{#1{%
    \ifx#2\else{ and #2}\fi}}

\newcommand\hidden[1]{\ifhidestuff%
    % not sure what to put here
    \else
        #1
    \fi}

\begin{document}

% The \hidden command seems to work fine on its own
The stuff between the quotes might be hidden: ``\hidden{stuff}''

% Now let's see if we can hide an optional argument to the \withoptarg command

This is the output I want when the flag is true: \withoptarg{this}{}

This is the output I want when the flag is false: \withoptarg{this}{that}


With my first approach, I instead get: \withoptarg{this}{\iftoggle{hidestuff}{}{that}}

With my second approach, I also get: \withoptarg{this}{\hidden{that}}

\end{document}

这是我得到的输出:

示例输出


更新:有问题的包是moderncv。我编写代码\withoptarg来模仿 的实现方式\cventry,以尽可能简化 MWE。但是——我的错——我使用的是过时的包版本。下一个版本包含作者的评论,它“纠正了与 中检查空参数的代码相关的几个错误\cventry”。事实上,升级到 的最新版本moderncv解决了我的问题。

如果我对\ifx工作原理的理解更深入一些,我可能已经识别出这个错误并意识到发生了什么。无论如何,我至少在这里学到了一些知识。

我将删除这个问题,但我会将其保留一段时间,只是为了感谢那些写信帮助的人的帮助。

答案1

您可以定义一个宏,根据-switch 传递\@gobble或。 您可以定义一个宏,根据-switch传递或。\@firstofone\if..
\@firstoftwo\@scondoftwo\if..

如果您希望在文本不可见的情况下保留水平/垂直空间,则可以使用\@firstoftwo/变量在和或类似的之间切换。\@scondoftwo\phantom{\mbox{text}}\@firstofone{\mbox{text}}

\documentclass{article}
\newif\ifhidestuff

\newcommand\StuffToHide{%
  \csname @\ifhidestuff gobbl\else firstofon\fi e\endcsname
}%

\newcommand\StuffToShowOrHide{%
  \csname @\ifhidestuff second\else first\fi oftwo\endcsname
}%

\newcommand\withoptarg[2][Optional Default]{%
  This is the optional argument in parentheses: (#1)\\
  This is the mandatory argument in parentheses: (#2)
}%

\parindent=0pt \parskip=\medskipamount

\begin{document}

\verb|\hidestufffalse|:\hidestufffalse

\withoptarg{Mandatory}

\withoptarg[\StuffToHide{Optional User-Provided}]{Mandatory}

\StuffToShowOrHide{\withoptarg[Optional User-Provided]}{\withoptarg}{Mandatory}

\StuffToShowOrHide{\withoptarg[Optional User-Provided]}{\withoptarg[]}{Mandatory}

\withoptarg[\csname\StuffToShowOrHide{@firstofone}{phantom}\endcsname{\mbox{Optional User-Provided}}]{Mandatory}

\medskip\hrule

\verb|\hidestufftrue|:\hidestufftrue

\withoptarg{Mandatory}

\withoptarg[\StuffToHide{Optional User-Provided}]{Mandatory}

\StuffToShowOrHide{\withoptarg[Optional User-Provided]}{\withoptarg}{Mandatory}

\StuffToShowOrHide{\withoptarg[Optional User-Provided]}{\withoptarg[]}{Mandatory}

\withoptarg[\csname\StuffToShowOrHide{@firstofone}{phantom}\endcsname{\mbox{Optional User-Provided}}]{Mandatory}

\end{document}

在此处输入图片描述



如果你想检查一个参数是否为空,即参数中根本不包含任何标记,我可以提供两种测试变体。
一种变体\CheckWhetherNullVanilla速度较慢,但​​不需要任何 TeX 扩展。它基于使用\string和应用括号黑客,同时确定}空参数后面的结束符是否被字符串化,或者{非空参数的第一个标记(不是开头的)是否被字符串化,或者{非空参数的第一个标记(开头的)是否被字符串化。
另一种变体\CheckWhetherNulleTeX速度更快,但需要 eTeX 扩展,因为它基于\detokenize,在这种情况下⟨一般文本⟩通过宏参数提供的为空表示根本不提供任何标记,否则将提供类别与类别不同的​​字符标记,$以便\ifcat可以使用该类别来完成这个技巧。(\ifcat$\detokenize{...}$...\else...\fi您也可以使用\if\relax\detokenize{...}\relax...\else...\fi,但这依赖于\relax不被重新定义来提供两个后续的相等标记,而我看到用户在本地范围内做各种奇怪的事情。)

除此之外,还有一个测试用于检查一个参数是否为空,即为空或仅包含明确的空格标记,,\CheckWhetherBlank它基于\CheckWhetherNullVanilla\CheckWhetherNulleTeX

测试寻找标记的存在,但它们不会扩展可扩展标记,因此,例如,\CheckWhetherNulleTeX{\empty}{empty}{not empty}产生not empty因为,虽然在扩展时只是消失并且没有产生任何标记,但\empty它本身是一个标记,因此\CheckWhetherNulleTeX的第一个参数不是空的,而是由标记 组成\empty

评论:

在随后的编码示例中,您会发现\romannumeral
乍一看这可能有点令人困惑。

在随后的编码示例中,\romannumeral它不用于获取任何数字的小写罗马表示,而是(ab?)用于触发大量扩展工作和翻转宏参数工作,以便在需要控制扩展的情况下不需要那么多/长的\expandafter链。

\romannumeral通常用于“吞食”形成 TeX-⟨数字⟩-数量,并作为回报,他们提供构成该 TeX 值的表示的字符标记-⟨数字⟩- 数量以小写罗马数字表示。
\romannumeral在任何情况下都会触发“吞噬”那些形成 TeX-⟨数字⟩-数量。但如果 TeX-⟨数字⟩-quantity 确实有一个非正值,默默地,即,没有错误消息或类似信息,根本没有传递任何令牌作为回报。
除此之外,在搜索属于 TeX-⟨数字⟩-数量,可扩展令牌的扩展不受抑制。

因此,你可以(滥用)使用\romannumeral来搜索属于 TeX-⟨数字⟩-quantity 让 (La)TeX 做大量的扩展工作和翻转宏参数工作,只要确保最终 TeX-⟨数字⟩- 发现数量的值不是正值。

在随后的编码示例中,作为“TeX-⟨数字⟩-其值不是正数”时使用了\chardef-token 。\UD@stopromannumeral

这样,宏的结果将在触发两个扩展步骤后传递,例如,在两次“命中”之后\expandafter

第一个传递顶层扩展,其第一个标记是\romannumeral

第二个触发执行\romannumeral例程,进而触发所有后续扩展步骤,直到出现结果。

如果您希望在表格环境/对齐等方面也能顺利运行,请确保用户提供的参数(可能包含类似 的内容)&嵌套在花括号中,直到最后一个扩展步骤提供结果。否则,&用户提供的参数中的 可能会在错误的时间点被用作表格单元格结尾的标记。

\documentclass[a4paper]{article}

\makeatletter
%%=============================================================================
%% PARAPHERNALIA:
%% \UD@firstoftwo, \UD@secondoftwo, \UD@stopromannumeral,
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%% In the following code \romannumeral is not used for
%%-----------------------------------------------------------------------------
%% Check whether argument is empty, slow, but no eTeX-extensions or
%% the like required:
%%.............................................................................
%% \CheckWhetherNullVanilla{<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>
\newcommand\CheckWhetherNullVanilla[1]{%
  \romannumeral\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{%
  \expandafter\UD@stopromannumeral\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty, based on \detokenize, thus eTeX-extensions
%% are required:
%%.............................................................................
%% \CheckWhetherNulleTeX{<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>}%
\newcommand\CheckWhetherNulleTeX[1]{%
  \romannumeral\ifcat$\detokenize{#1}$%
  \expandafter\expandafter\expandafter\UD@stopromannumeral
  \expandafter\UD@firstoftwo\else
  \expandafter\expandafter\expandafter\UD@stopromannumeral
  \expandafter\UD@secondoftwo\fi
}%
%%-----------------------------------------------------------------------------
%% Check whether argument is blank (empty or only explicit space-tokens):
%%-----------------------------------------------------------------------------
%% -- Take advantage of the fact that TeX discards space tokens when
%%    "fetching" _un_delimited arguments: --
%% \CheckWhetherBlank{<Argument which is to be checked>}%
%%                   {<Tokens to be delivered in case that
%%                     argument which is to be checked is blank>}%
%%                   {<Tokens to be delivered in case that argument
%%                     which is to be checked is not blank>}%
%% Instead of \CheckWhetherNulllVanilla you can as well use
%% \CheckWhetherNullleTeX
\newcommand\CheckWhetherBlank[1]{%
  \romannumeral\expandafter\expandafter\expandafter\UD@secondoftwo
  \expandafter\CheckWhetherNullVanilla\expandafter{\UD@firstoftwo#1{}{}}%
}%
\makeatother

\parindent=0pt \parskip=\medskipamount

\begin{document}

\verb|\CheckWhetherNullVanilla{}{empty}{not empty}|:\\
\CheckWhetherNullVanilla{}{empty}{not empty}

\verb|\CheckWhetherNulleTeX{}{empty}{not empty}|:\\
\CheckWhetherNulleTeX{}{empty}{not empty}

\verb|\CheckWhetherBlank{}{blank}{not blank}|:\\
\CheckWhetherBlank{}{blank}{not blank}

\medskip\hrule

\verb|\CheckWhetherNullVanilla{ }{empty}{not empty}|:\\
\CheckWhetherNullVanilla{ }{empty}{not empty}

\verb|\CheckWhetherNulleTeX{ }{empty}{not empty}|:\\
\CheckWhetherNulleTeX{ }{empty}{not empty}

\verb|\CheckWhetherBlank{ }{blank}{not blank}|:\\
\CheckWhetherBlank{ }{blank}{not blank}

\medskip\hrule

\verb|\CheckWhetherNullVanilla{{some}thing}{empty}{not empty}|:\\
\CheckWhetherNullVanilla{{some}thing}{empty}{not empty}

\verb|\CheckWhetherNulleTeX{{some}thing}{empty}{not empty}|:\\
\CheckWhetherNulleTeX{{some}thing}{empty}{not empty}

\verb|\CheckWhetherBlank{{some}thing}{blank}{not blank}|:\\
\CheckWhetherBlank{{some}thing}{blank}{not blank}

\medskip\hrule

\verb|\CheckWhetherNullVanilla{something}{empty}{not empty}|:\\
\CheckWhetherNullVanilla{something}{empty}{not empty}

\verb|\CheckWhetherNulleTeX{something}{empty}{not empty}|:\\
\CheckWhetherNulleTeX{something}{empty}{not empty}

\verb|\CheckWhetherBlank{something}{blank}{not blank}|:\\
\CheckWhetherBlank{something}{blank}{not blank}

\medskip\hrule

\verb|\CheckWhetherNullVanilla{\empty}{empty}{not empty}|:\\
\CheckWhetherNullVanilla{\empty}{empty}{not empty}

\verb|\CheckWhetherNulleTeX{\empty}{empty}{not empty}|:\\
\CheckWhetherNulleTeX{\empty}{empty}{not empty}

\verb|\CheckWhetherBlank{\empty}{blank}{not blank}|:\\
\CheckWhetherBlank{\empty}{blank}{not blank}

\end{document}

在此处输入图片描述

相关内容