如何可靠地获取未定义的控制序列标记?

如何可靠地获取未定义的控制序列标记?

如何可靠地获取当前范围内未定义的控制序列标记?

例如,是否有一个 token 序列⟨东西⟩你可以做

\begingroup\expandafter\endgroup\expandafter\dosomething\csname ⟨stuff⟩\endcsname

以便

  • TeX 在从 -expression 生成控制序列标记时不会提供任何错误消息\csname..\endcsname,并且
  • \dosomething无论如何,处理后得到的后面的控制序列标记都是未定义的\endgroup

我可以使用它来可靠地让另一个控制序列标记等于未定义的东西。

现在我做了类似的事情,并希望在执行分配之前\let\token=\UndeFineD没有第三方代码定义。\UndeFineD\let

另一种方法可以是循环构造控制序列标记的名称,直到找到一个,其中测试如下

\DeclareRobustCommand\CheckWhetherDefined[1]{%
  \begingroup
  \expandafter\ifx\csname#1\endcsname\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {%
    \expandafter\endgroup\expandafter\ifx\csname#1\endcsname\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  }{\endgroup\@firstoftwo}%
}%

或者类似

\DeclareRobustCommand\CheckWhetherDefined[1]{%
  \ifcsname#1\endcsname\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%

确实收益\@secondoftwo

但我想知道是否还有更聪明的方法。

也许是一个\csname..\endcsname-expression的边缘情况 - 与使用“frozen-”的情况具有类似的“边缘性”,\relax在这种情况下您需要一个肯定不是显式字符标记并且绝对不会根据定义的标记\outer


请注意,问题的重点不在于测试控制序列标记是否已定义/未定义的方法。

我寻求获取当前范围内未定义的控制序列标记的最佳方法。

在这种情况下,“定义性/未定义性”的测试只是一种达到目的的手段,例如,如果一个人选择创建标记的路径,直到创建一个未定义的标记。


“学术问题”:TeX 中是否存在一种易于实现的方法来枚举所有可能的控制序列名称?

答案1

即使没有 e-TeX,下面的方法也应该可以工作。它在组内构建控制序列名称,检查\relax,如果它们相等则关闭该组,重新检查,\relax并且只有当后者检查为假时才使用结果控制序列。

控制序列名称是使用数字名称构建的(并且如果每个数字名称都以一个点开头,则在名称前面放置越来越多的点,直到找到未定义的 cs)。

\begingroup
\catcode`\@=11
\long\def\@firstofone#1{#1}
\@firstofone{\endgroup
\long\def\@secondofthree#1#2#3{#2}
\long\def\@secondoftwo#1#2{#2}
\newcount\undefinedto@count
\newcount\undefinedto@maxcount
\undefinedto@maxcount=2147483647
\long\def\undefinedto#1%
  {%
    \undefinedto@{}%
    {#1}%
  }
\def\undefinedto@
  {%
    \begingroup
    \global\undefinedto@count=-\undefinedto@maxcount
    \undefinedto@loop
  }
\def\undefinedto@loop#1%
  {%
    \expandafter\undefinedto@loop@
      \csname #1\the\undefinedto@count\endcsname
      {#1}%
  }
\long\def\undefinedto@loop@#1#2%
  {%
    \ifx#1\relax
      \expandafter\@secondofthree
    \fi
    \@secondoftwo
      {\undefinedto@test#1{#2}}%
      {\undefinedto@loop@next{#2}}%
  }
\def\undefinedto@loop@next#1%
  {%
    \ifnum\undefinedto@count=\undefinedto@maxcount
      \expandafter\@secondofthree
    \fi
    \@secondoftwo
      {%
        \global\undefinedto@count=-\undefinedto@maxcount
        \undefinedto@loop{#1.}%
      }%
      {%
        \global\advance\undefinedto@count1
        \undefinedto@loop{#1}%
      }
  }
\long\def\undefinedto@test#1#2%
  {%
    \endgroup
    \ifx#1\relax
      \expandafter\@secondofthree
    \fi
    \@secondoftwo
      {%
        \begingroup
        \undefinedto@loop@next{#2}%
      }%
      {\undefinedto@found#1}%
  }
\long\def\undefinedto@found#1#2{#2#1}
}

\undefinedto\show

答案2

您可以随机抽样控制序列名称,直到找到尚未定义的控制序列名称

pdfTeX 专用

\catcode`@=11

\long\def\@firstoftwo#1#2{#1}
\long\def\@secondoftwo#1#2{#2}

\long\def\@ifcsname#1{%
  \ifcsname #1\endcsname
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}

\long\def\@uniquecsname#1{%
  \@ifcsname{#1}%
    {\expandafter\@uniquecsname\expandafter{\number\pdfuniformdeviate\maxdimen}}%
    {#1}%
}

\def\uniquecsname{\expandafter\@uniquecsname\expandafter{\number\pdfuniformdeviate\maxdimen}}

\begingroup\expandafter\endgroup\expandafter\meaning\csname\uniquecsname\endcsname

\bye

答案3

以下内容在精神上与 Henri 的回答类似,但在循环中可预测地构建控制序列名称,而不是使用随机数。

这应该在每个带有 e-TeX 的引擎中工作。

\begingroup
\catcode`\@=11
\catcode`\^^@=12
\unexpanded{\endgroup
\protected\def\provideundefinedcsto#1%
  {%
    \begingroup
      \expandafter
    \endgroup
    \expandafter#1\csname\provideundefinedcsto@{^^@}\endcsname
  }
\def\provideundefinedcsto@#1%
  {%
    \ifcsname #1\endcsname\expandafter\@secondoftwo\fi
    \@gobble{\provideundefinedcsto@{#1^^@}}^^@%
  }
\long\def\@secondoftwo#1#2{#2}
\long\def\@gobble#1{}
}

\provideundefinedcsto\show
\bye

答案4

我认为你无法避免使用 e-TeX,特别是\ifcsname。如果你的目标是真的取消定义某些标记,您可以使用整数进行循环,这样可以避免长字符串。

\def\undefine#1{%
  \begingroup
  \count255=0
  \buildundefined
  \expandafter\endgroup\expandafter\let\expandafter#1\csname\the\count255\endcsname
}
\def\buildundefined{%
  \immediate\write20{Testing \the\count255}% for debugging
  \ifcsname\the\count255\endcsname
    \advance\count255 by 1
    \expandafter\buildundefined
  \fi
}

% just for testing
\def\token{token}
\def\0{}
\def\1{}
\def\2{}

\immediate\write20{\noexpand\token is \meaning\token}

\undefine\token

\immediate\write20{\noexpand\token is \meaning\token}

\immediate\write20{\meaning\3}

\bye

控制台输出是

\token is macro:->token
Testing 0
Testing 1
Testing 2
Testing 3
\token is undefined
undefined

最后一行显示,\let在本例中\3,所使用的控制序列在作业结束时仍然未定义。

相关内容