是否有“\ReallyDontExpandUntilTheLastMinute”命令?

是否有“\ReallyDontExpandUntilTheLastMinute”命令?

我想要做的几件事非常相似,基本上涉及将宏扩展保留到最后一刻。

可能最简单的例子是,我有一组宏,它们扩展为“X 中的对象”的变体,但有时我会覆盖默认值。因此,while\cobj扩展为“C 中的对象”,\sobj扩展为“集合”,\gobj扩展为“组”。当我想谈论一个对象。一般来说,我应该输入“an \cobj”,但在特定情况下,我可能需要更改为“a \sobj”。困难在于,使用这些宏的一个原因是我可以改变主意,确定哪些宏有特殊名称,哪些没有。但如果我必须重新将所有“an”重写为“a”,那么(部分)目的就落空了。所以我想做的是定义一个宏“\a”,检查下一个字符是否为元音,并适当地生成“an”或“a”(模数奇数特殊情况!)。

困难之处在于它后面不是字符,而是宏。所以我需要扩展该宏来找出最终的第一个字符。如果它是一个简单的宏,那么\def\cobj{object in C}我只需执行\def\a{\noexpand\@a}\def\@a{\@ifnextchar{a}{an}{\@ifnextchar{e}{an}...},但\cobj它是一个相当复杂的宏,在实际到达最终字符之前需要扩展几个级别。特别是,\cobj接受一个可选参数。

所以我希望能够\a在最后一刻进行扩展。有点像\noexpand,但这只会对一跳进行不扩展,而不是“结束 - 1”跳。

有人知道该怎么做吗?为了表明可以接受的答案水平,我知道,\expandafter而且我不怕使用它!


编辑:这是另一个稍微复杂一点的例子。在与上述情况类似的情况下,我有\dcat一个“类别 D”的例子。在少数情况下,我想“吃掉”“the”,所以我想要一个\nothe可以预先设置的命令:\nothe\dcat它会吃掉它后面的第一个单词。编写一个命令来吞掉下一个单词很简单输入流,但我想要输出消失。

答案1

另一个回答可以解决您的问题,但不能解决您的问题,那么创建一个“\newobject”命令怎么样?您可以在其中指定它是“a”还是“an”(然后您就不会遇到任何异常!)并为您提供一组命令以根据需要进行排版。例如

\newobject{Gobj}{a}{group}
\newobject{Aobj}{an}{axiom}

\Gobj     % group
\aGobj    % a group
\theGobj  % the group

\Aobj     % axiom
\aAobj    % an axiom
\theAobj  % the axiom

当然,您可以定义替代接口,例如\A\GObj\The{gobj}或任何对您来说更好的接口。

答案2

编译时,下面的文件会生成两个包,然后在下面的测试文件中使用它们。

\documentclass{article}
\usepackage{nextword}
\ExplSyntaxOn
\newcommand { \nothe }
  { \nextword_do:n { \str_if_eq:xxF {\g_nextword_tl} {the} {\g_nextword_tl} } }
\ExplSyntaxOff
\begin{document}
\newcommand{\obj}[1][the default]{#1 object}
\nothe Hello, \unskip\nothe the World!
\nothe \obj [Any] is nice, including\nothe\obj s.
\end{document}

第一个包提供了“扩展”完整 token 的工具,在此过程中执行一些 TeX 原语。这使我们能够接近 TeX 的输出。在此基础上构建包nextword,它在输出时抓取以下单词(当前“单词”在下一个空格处停止,将其留在输出中)。单词保存在 中。如果不是 ,则测试文件中定义的\g_nextword_tl命令会将其放回。\nothe\g_nextword_tlthe

\RequirePackage{filecontents}

\begin{filecontents}{sex.sty}
%% Package sex "Strong expansion for LaTeX"
\RequirePackage{expl3}
\ProvidesExplPackage{sex}{2011/07/12}{v<3}{Strong expansion for LaTeX}
\tl_new:N \g_sex_tl
\cs_new:Npn \sex:nf #1
  {
    \tl_gset:Nn \g_sex_tl {#1}
    \sex_aux:
  }
\cs_new:Npn \sex_aux:
  {
    \group_begin:
    \int_set:Nn \tex_escapechar:D { -1 }
    \group_align_safe_begin:
    \sex_peek:
  }
\cs_new:Npn \sex_peek: { \peek_after:Nw \sex_test: }
\cs_new:Npn \sex_test:
  {
    \token_if_expandable:NTF \l_peek_token
      { \exp_after:wN \sex_peek: }
      {
        \cs_if_exist:cTF
          { sex_ \token_to_meaning:N \l_peek_token : }
          {
            \group_align_safe_end:
            \exp_args:Nc \group_end:
              { sex_ \token_to_meaning:N \l_peek_token : }
          }
          {
            \token_if_group_begin:NTF \l_peek_token
              { \sex_bgroup: }
              {
                \token_if_group_end:NTF \l_peek_token
                  { \sex_egroup: }
                  {
                    \token_if_eq_meaning:NNTF \l_peek_token \c_space_token
                      { \sex_space: }
                      { \sex_stop: }
                  }
              }
          }
      }
  }
\cs_new:Npn \sex_stop:
  {
    \group_align_safe_end:
    \group_end:
    \g_sex_tl
  }
% Execute the following token (which may be {, ,}) before "\sex_aux".
\cs_new:Npn \sex_swap:
  {
    \group_align_safe_end:
    \group_end:
    \tex_afterassignment:D \sex_swap_aux:
    \cs_gset_eq:NN \g_sex_token
  }
\cs_new:Npn \sex_swap_aux: { \g_sex_token \sex_aux: }
\cs_new_eq:NN \sex_bgroup:     \sex_swap:
\cs_new_eq:NN \sex_egroup:     \sex_swap:
\cs_new_eq:NN \sex_space:      \sex_swap:
\cs_new_eq:NN \sex_begingroup: \sex_swap:
\cs_new_eq:NN \sex_endgroup:   \sex_swap:
\cs_new_eq:NN \sex_relax:      \sex_swap:
% Assignments: do the assignment, then regain control.
\cs_new:Npn \sex_assignment:
  { \tex_afterassignment:D \sex_aux: }
\cs_new_eq:NN \sex_let:         \sex_assignment:
\cs_new_eq:NN \sex_futurelet:   \sex_assignment:
\cs_new_eq:NN \sex_def:         \sex_assignment:
\cs_new_eq:NN \sex_edef:        \sex_assignment:
\cs_new_eq:NN \sex_gdef:        \sex_assignment:
\cs_new_eq:NN \sex_xdef:        \sex_assignment:
\cs_new_eq:NN \sex_long:        \sex_assignment:
\cs_new_eq:NN \sex_global:      \sex_assignment:
\cs_new_eq:NN \sex_protected:   \sex_assignment:
\cs_new_eq:NN \sex_escapechar:  \sex_assignment:
\cs_new_eq:NN \sex_endlinechar: \sex_assignment:
\cs_new_eq:NN \sex_catcode:     \sex_assignment:
% Document command
\cs_new_eq:NN \StrongExpand \sex:nf
\end{filecontents}


\begin{filecontents}{nextword.sty}
%% Package nextword "Catch the next word in the output."
\RequirePackage{sex}
\ProvidesExplPackage{nextword}{2011/07/12}{v0}{Next word of output}
\tl_new:N \g_nextword_tl
\tl_new:N \g_nextword_action_tl
\cs_new_protected:Npn \nextword_do:n #1
  {
    \tl_gset:Nn \g_nextword_action_tl {#1}
    \tl_gclear:N \g_nextword_tl
    \sex:nf
      {
        \cs_gset:Npn \sex_space:
          {
            \cs_gset_eq:NN \sex_space: \sex_swap:
            \tl_gset_eq:NN \g_sex_tl \g_nextword_action_tl
            \sex_stop:
          }
        \nextword_loop:N
      }
  }
\cs_new_protected:Npn \nextword_loop:N #1
  {
    \token_if_cs:NTF #1
      {
        \cs_gset_eq:NN \sex_space: \sex_swap:
        \g_nextword_action_tl
        #1
      }
      {
        \tl_put_right:Nx \g_nextword_tl
          {
            \exp_after:wN \nextword_meaning_to_char:w
            \token_to_meaning:N #1
          }
          \sex:nf { \nextword_loop:N }
      }
  }
\cs_new:Npn \nextword_meaning_to_char:w #1 ~ #2 ~ %
  {
    \prg_case_str:nnn {#1}
      {
        {math}       { \nextword_meaning_to_char_aux:w }
        {alignment}  { \nextword_meaning_to_char_aux:w }
        {macro}      { \nextword_meaning_to_char_aux:w }
      }
      { }
  }
\cs_new:Npn \nextword_meaning_to_char_aux:w #1 ~ { }
\end{filecontents}

% ===== Test file.
\documentclass{article}
\usepackage{nextword}
\ExplSyntaxOn
\newcommand { \nothe }
  { \nextword_do:n { \str_if_eq:xxF {\g_nextword_tl} {the} {\g_nextword_tl} } }
\ExplSyntaxOff
\begin{document}
\newcommand{\obj}[1][the default]{#1 object}
\nothe Hello, \unskip\nothe the World!
\nothe \obj [Any] is nice, including\nothe\obj s.
\end{document}

答案3

如今,不使用 eTeX 已经没有什么意义了(所有扩展的 TeX 变体,如 PDFTeX、LuaTeX 或 XeTeX 都包含它),并且用\protected\def及其变体定义的宏只有在使用 或显式扩展时才会扩展\expandafter。在 writes 和 edefs 内部,它们保持不变。当然,这不会扩展到它们的任何参数,因为在宏实际扩展之前,它们不被视为参数。

答案4

完全扩展具有非固定数量参数的东西是相当困难的,至少除非你知道足够多的知识来自己掌握它们。原因是,就 TeX 而言,你的“最后可能扩展时刻”当读取 token 时。TeX 知道,你\a可以改变后续宏的含义、类别代码、ETC

您能否更详细地介绍一下可选参数的性质。可以有一个完全可扩展的宏,它接受可选参数(请参阅 xparse 了解一种方法),因此您可以想象设计它,\a以便它查找可选参数,在适当的情况下抓取它,执行\edeffor\cobj并最终执行您想要执行的操作。

相关内容