定义命令来像 \ifvar 一样工作

定义命令来像 \ifvar 一样工作

我正在尝试操作多个布尔变量,这些变量简单命名为,,,one等等,并且因为我将它们与计数器一起使用,所以我定义了一些命令来接受数字输入并处理布尔值:twothree

\newif\ifp@one@
\newif\ifp@two@
\newif\ifp@three@

\def\p@settrue@#1{
  \ifnum#1 =1 \p@one@true \else
  \ifnum#1 =2 \p@two@true \else
  \ifnum#1 =3 \p@three@true
  \fi\fi\fi}

\def\p@setfalse@#1{<same as with true>}

\def\p@if@#1{
  \ifnum#1 =1 \expandafter\ifp@one@ \else
  \ifnum#1 =2 \expandafter\ifp@two@ \else
  \ifnum#1 =3 \expandafter\ifp@three@
  \fi\fi\fi}

前两个命令工作正常,所以如果我运行\p@settrue@1,那么\ifp@one@现在就是true

第三个函数的问题在于\p@if@:我无法让它工作。我以为只需\expandafter在每个函数前添加一个\ifp@<number>@,但这个函数不起作用。

理想情况下,我希望使用它

\p@if@1
   <do something>
\else
   <do something else>
\fi

为什么这不起作用?


我意识到我可以定义

\def\p@if@#1#2#3{
  \ifnum#1 =1 \ifp@one@#2\else#3\fi \else
  \ifnum#1 =2 \ifp@two@#2\else#3\fi \else
  \ifnum#1 =3 \ifp@three@#2\else#3\fi 
  \fi\fi\fi}

这是一个不错的选择,但我仍然好奇为什么上面的代码会失败。

答案1

建立从数字到文本表示的转换表:

\catcode`@=11

\def\p@translate#1{%
  \ifcase#1\or one\or two\or three\fi
}
\def\p@settrue@#1{%
  \csname p@\p@translate{#1}@true\endcsname
}
\def\p@setfalse@#1{%
  \csname p@\p@translate{#1}@false\endcsname
}
\def\p@cond@#1{%
  TT\fi
  \csname ifp@\p@translate{#1}@\endcsname
}

\newif\ifp@one@
\newif\ifp@two@
\newif\ifp@three@

% Testing
\def\msg#{\immediate\write16}
\p@settrue@{1}
\if\p@cond@{1}\msg{1 = true}\else\msg{1 = false}\fi
\if\p@cond@{3}\msg{3 = true}\else\msg{3 = false}\fi

\bye

由于不可能有一个像跳过的文本中的条件一样正确运行的宏,因此TT\fi使用了这个技巧,因此你调用

\if\p@cond@{1}%
  <text to be executed if conditional 1 is true>%
\else
  <text to be executed if conditional 1 is false>%
\fi

输出:

1 = true
3 = false

答案2

由于嵌套结构, 的定义\p@if@未按预期工作\if。需要更多 来\expandafter清理结束\else\fi标记。

以下示例使用\csname构造来简化清理并更改语法。\iftrue位于 之前\p@if@。 后者是一个宏,TeX 不会将其识别为\if命令的一部分。 当 TeX 跳过分支时,它不会检查宏。 构造也可以在构造\iftrue\p@if@内部使用。\if

\catcode`\@=11

\newif\ifp@one@
\newif\ifp@two@
\newif\ifp@three@

\def\p@settrue@#1{
  \ifcase#1\or
    \p@one@true\or
    \p@two@true\or
    \p@three@true
  \fi
}
\def\p@setfalse@#1{
  \ifcase#1\or
    \p@one@false\or
    \p@two@false\or
    \p@three@false
  \fi
}

\def\p@if@#1{%
  \fi
  \csname if%
    \ifcase#1false\or
      \ifp@one@ true\else false\fi\or
      \ifp@two@ true\else false\fi\or
      \ifp@three@ true\else false\fi\else
      false%
    \fi
  \endcsname
}

% Testing
\def\msg#{\immediate\write16}
\p@settrue@1
\iftrue\p@if@1\msg{1 = true}\else\msg{1 = false}\fi
\iftrue\p@if@3\msg{3 = true}\else\msg{3 = false}\fi

\csname @@end\endcsname\end

结果:

1 = true
3 = false

相关内容