如何制作中缀 \if 变体?

如何制作中缀 \if 变体?

如何\if在核心 TeX 中制作自定义变体?

我想写:

\ifshape{it} ... \else ... \fi

例如:

\textit{Italic? \ifshape{it}Yes\else No\fi}

\ifshape问题是,当我定义为时,出现错误“太多}”

\makeatletter
\newcommand{\ifshape}[1]{%
  \def\ifshape@test{#1}%
  \ifx\f@shape\ifshape@test%
}
\makeatother

构造\if...\else...\fi是否真的具有词法作用域?我不认为 (La)TeX 具有词法作用域。我期望上述内容(定义加调用)扩展为:

\def\ifshape@test{it}\ifx\f@shape\ifshape@test Yes\else No\fi

当然,如果我这样写,效果会很好:

\makeatletter
\newcommand{\ifshapethenelse}[3]{%
  \def\ifshape@test{#1}%
  \ifx\f@shape\ifshape@test{#2}\else{#3}\fi%
}
\makeatother

但是我想使用中缀表示法而不是前缀表示法来写,因为现在@DavidCarlisle 已经向我指出\ifthenelse(来自包ifthen)是一个中缀怪物并且实际上并没有做任何神奇的事情。

我是否需要在某处插入\relax\noexpand的某种组合才能使其工作?

答案1

问题在于的扩展\textit以条件开始:

\ifmmode
  \nfss@text {\itshape #1}%
\else
  \hmode@bgroup\text@command{#1}\itshape\check@icl
  #1%
  \check@icr\expandafter\egroup
\fi

让我们看看当你提出#1论点时会发生什么:

\ifmmode
  \nfss@text {\itshape Italic? \ifshape{it}Yes\else No\fi}%
\else
  \hmode@bgroup\text@command{Italic? \ifshape{it}Yes\else No\fi}\itshape\check@icl
  Italic? \ifshape{it}Yes\else No\fi
\check@icr\expandafter\egroup
\fi

问题在于:你的参数的\elseand匹配:你不在数学模式中,因此会遵循“false”路径,然后找到多余的右括号。宏是\fi\ifmmode\ifshape不是扩展,因为它处于“真实”路径中。

解决这个问题的通常方法是

\makeatletter
\newcommand{\ifshape}[1]{%
  \def\f@shapetest{#1}%
  \ifx\f@shape\f@shapetest
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}
\makeatother

并称之为

\textit{Italic? \ifshape{it}{Yes}{No}}

在这种情况下,直到扩展时才会看到\else或,并且它们将正确引用。\fi\ifshape\ifx

另一种方法是说

\makeatletter
\newcommand\isshape[1]{%
  TT\fi
  \def\f@shapetest{#1}%
  \ifx\f@shape\f@shapetest}
\makeatother

可以称之为

\textit{Italic? \if\isshape{it}Yes\else No\fi}

这是一个值得仔细研究的技巧(它是由大魔法师自己设计的)。

这个技巧是什么?它基于这样的事实:\if想要在它后面找到两个不可扩展的标记。当\if在扩展上下文中找到时,它会扩展\isshape并立即发现TT相等,因此 TeX 会遵循“真”分支,该分支为空,而后面的分支\fi会消失。如果改用TL,TeX 会遵循“假”分支,该分支也是空的!

接下来,可能在其他标记之后,是真正让我们关心的条件,它会像往常一样进行评估。

如果\if\isshape在非扩展上下文中发现 ,例如在另一个条件的“假”分支中,我们打算执行内部条件的工作的\else和让 TeX 满意,因为它们与“假” 配对。\fi\if

唯一重要的是这两个令牌是不可扩展的,因此\relax\relax\hfuzz\uchyph也可以起作用。

答案2

如果你愿意将测试的语法稍微改变一下\ifshape{it}\then Yes\else No\fi,你也可以使用 Donald Arseneau 提出的以下技巧(来自\ifnum 表示实数comp.text.tex 上的线程) :

\documentclass{article}

\makeatletter
\let\then\iffalse
\def\ifshape#1\then{%
  \def\ifshape@test{#1}%
  \ifx\f@shape\ifshape@test
}
\makeatother

\begin{document}

\textit{Italic? \ifshape{it}\then Yes\else No\fi}

\textbf{Italic? \ifshape{it}\then Yes\else No\fi}

\end{document}

相关内容