在循环中使用 \g@addto@macro

在循环中使用 \g@addto@macro

\g@addto@macro在循环中使用时我感到困惑。我的代码是:

\documentclass{article}

\usepackage{ifthen}
\usepackage{newfile}
\usepackage{xstring}

\makeatletter

\DeclareRobustCommand\@initial[1]{#1}
\DeclareRobustCommand\initial[1]{%
    \StrLeft{#1}{1}[\firstletter]%
    \@initial{\firstletter}}

\newcounter{authors@count}
\newcommand\authors[2]{
    \stepcounter{authors@count}
    \expandafter\gdef\csname @author@first\arabic{authors@count}\endcsname{#1}
    \expandafter\gdef\csname @author@last\arabic{authors@count}\endcsname{#2}
}

\newcounter{i}
\def\authorsliststring{}
\def\authorslist{%
    \whiledo{\value{i} < \value{authors@count}}{%
        \stepcounter{i}%
        \@nameuse{@author@last\thei}\space% for test only
        \initial{\@nameuse{@author@first\thei}}.% for test only
        \g@addto@macro\authorsliststring{%
            \@nameuse{@author@last\thei} 
            \initial{\@nameuse{@author@first\thei}}.}%
        \ifthenelse{\thei = \theauthors@count}{}
            {,\space% for test only
                \g@addto@macro\authorsliststring{, }%
        }%
    }
}

\newcommand\writetoc{
    \newoutputstream{txt}
    \openoutputfile{\jobname.txt}{txt}
    \addtostream{txt}{\authorsliststring}
    \closeoutputstream{txt}
}

\makeatother

\begin{document}

\authors{Alex}{Andersson}
\authors{Barbara}{Brown}
\authors{Charles}{Chaplin}

\authorslist

\authorsliststring

\writetoc

\end{document}

\authors在开发我的类时,使用重复命令将 First Name 和 Nast Name 分别写入单独的变量中对我来说很方便。稍后,使用单独的\authorslist宏,我生成\authorsliststring字符串作为 Last Name 和 First Name 的第一个字符(这里有一个很长的解释,说明为什么我需要在单独的\authorslist命令中执行此操作以及为什么我需要\initial这种方式的命令,但我需要这样)。\authorsliststring然后在类中的正确位置使用该字符串并将其写入文件,以便稍后从其他 TeX 文件生成目录。我需要在\authorsliststring文件中获取相同的内容 - “Andersson A., Brown B., Chaplin C。”

然而,在屏幕上我看到:

1

然后我进入文件:

Chaplin \initial {Charles}., Chaplin \initial {Charles}., Chaplin \initial {Charles}.

此外,我不明白如何写入文件,不是\initial {Charles},但是C.

答案1

宏组合的作用\initial——\@initial对我来说并不完全清楚。

似乎\initial是一种宏机制,它在内部使用\@initial\StrLeft在某些时候定义宏\firstletter以扩展为作者名字的首字母。

只要在你的\authorslist-recursion/ \whiledo-recursion 中你正确地分离了哪些操作是可扩展的,哪些操作是不可扩展的 - 例如,\StrLeft(因此也是\initial)不是,你可以结合(ab?)使用的技巧\romannumeral来保持 TeX 触发扩展,直到遇到\UD@stopromannumeral交换宏参数的技巧,以便让 TeX一次性排列\g@addto@macro-directive 的标记以添加名称:\authorsliststring

\documentclass{article}

\usepackage{ifthen}
\usepackage{newfile}
\usepackage{xstring}

\makeatletter
\newcommand\UD@Exchange[2]{#2#1}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%

% Assume \initial is a function/macro-mechanism which at some point defines the macro 
% \ScratchmacroForFirstLetter to deliver the first letter of the first name.
% ( \initial itself probably is not fully expandable, e.g., due to calling \StrLeft
%   or ehatever,  which in turn is not fully expandable. In any case in the end
%   the macro \ScratchmacroForFirstLetter is defined. )
\newcommand\ScratchmacroForFirstLetter{}%
\@ifdefinable\initial{%
  \DeclareRobustCommand\initial[1]{\StrLeft{#1}{1}[\ScratchmacroForFirstLetter]}%
}%

\newcounter{authors@count}
\newcommand\authors[2]{%
    \stepcounter{authors@count}%
    \global\@namedef{@author@first\arabic{authors@count}}{#1}%
    \global\@namedef{@author@last\arabic{authors@count}}{#2}%
}

\newcounter{i}%
\newcommand*\authorsliststring{}%
\newcommand*\authorslist{%
    \ifnum\value{i} < \value{authors@count}% Why \whiledo if the recursion can be done without? ;-)
        \stepcounter{i}%
        % ==============================================================================================
        % Typeset the name of the author:
        % ----------------------------------------------------------------------------------------------
        % - Typeset the first name and a space:
        \@nameuse{@author@last\thei} %
        % - Somehow get the first letter of the first name of the author into the macro
        %   \ScratchmacroForFirstLetter - this is the job of \initial:
        \initial{\@nameuse{@author@first\thei}}%
        % - Apply  \ScratchmacroForFirstLetter for typesetting the first letter of the first name of
        %   the author, trailed by a dot:
        \ScratchmacroForFirstLetter.%
        % - Probably typeset a comma and a space:
        \ifthenelse{\thei = \theauthors@count}{}{, }%
        % ==============================================================================================
        % Add the name of the author to the macro \authorsliststring:
        % ----------------------------------------------------------------------------------------------
        %  - Somehow get the first letter of the first name of the author into the macro
        %    \ScratchmacroForFirstLetter - this is the job of \initial:
        \initial{\@nameuse{@author@first\thei}}%
        %  - From now on everything else can be done by means of expansion-methods -
        %    do some argument-exchanging-trickery via \UD@Exchange for lining up the tokens within
        %    the brace-group which encloses the last argument of the \g@addto@macro-directive;
        %    within the brace-group which encloses the last argument of the \g@addto@macro-directive
        %    use \romannumeral for keeping expansion going until TeX sees \UD@stopromannumeral:
        \expandafter\g@addto@macro\expandafter\authorsliststring\expandafter{%
          \romannumeral
          \ifnum\value{i}=\value{authors@count}\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi    
          {\UD@Exchange{}}{\UD@Exchange{, }}%
          {%
            \expandafter\UD@Exchange\expandafter{%
               \ScratchmacroForFirstLetter.%
            }{%
              \expandafter\expandafter\expandafter\UD@stopromannumeral
              \csname @author@last\thei\expandafter\endcsname\@firstofone{ }%
            }%
          }%
        }%
    \expandafter\authorslist\fi
}

\newoutputstream{txt}%
\newcommand\writetoc{%
    \openoutputfile{\jobname.txt}{txt}%
    \addtostream{txt}{\authorsliststring}%
    \closeoutputstream{txt}%
}

\makeatother

\begin{document}

\authors{Alex}{Andersson}
\authors{Barbara}{Brown}
\authors{Charles}{Chaplin}

\setcounter{i}{0}%
\authorslist

\texttt{\vrule\string\authorsliststring=\meaning\authorsliststring\vrule}

\authorsliststring

\writetoc

\end{document}

在此处输入图片描述


说实话,对我来说这似乎没有必要那么复杂。使用 expl3 而不是 xstring 的\StrLeft,名字的首字母可能可以通过 获得\str_head_ignore_spaces:n,它是可扩展的:

\documentclass{article}

\usepackage{newfile}

\ExplSyntaxOn
\clist_new:N  \__MyStuff_Authors_clist
\cs_new_protected:Npn \authors #1#2 
  {
    \clist_gput_right:Nx \__MyStuff_Authors_clist 
                         {{#2~\str_head_ignore_spaces:n{#1}.}}
  }
\cs_new:Npn \authorslist 
  {  \clist_use:Nnnn \__MyStuff_Authors_clist {,~}{,~}{,~}  }
\ExplSyntaxOff

\newoutputstream{txt}%
\newcommand\writetoc{%
    \openoutputfile{\jobname.txt}{txt}%
    \addtostream{txt}{\authorslist}%
    \closeoutputstream{txt}%
}

\begin{document}

\authors{Alex}{Andersson}
\authors{Barbara}{Brown}
\authors{Charles}{Chaplin}

\noindent
\authorslist

\writetoc

% Let's see the content of  \jobname.txt - with older LaTeX-releases
% you might need to add   \usepackage{verbatim}  to the preamble for
% this to work out, but seems the package  newfile  already does that
% for you:

\verbatiminput{\jobname.txt}

\end{document}

在此处输入图片描述

答案2

如评论中所述,\thei需要在的参数中展开\g@addto@macro。在这里,我通过保存完全展开的定义(需要进行几次展开)\thei来实现这一点,然后在定义中使用足够的s(简写为)来用其展开替换 的出现。\Thei\expandafter\z\Thei

\documentclass{article}

\usepackage{ifthen}
\usepackage{newfile}
\usepackage{xstring}

\makeatletter

\DeclareRobustCommand\@initial[1]{#1}
\DeclareRobustCommand\initial[1]{%
    \StrLeft{#1}{1}[\firstletter]%
    \@initial{\firstletter}}

\newcounter{authors@count}
\newcommand\authors[2]{
    \stepcounter{authors@count}
    \expandafter\gdef\csname @author@first\arabic{authors@count}\endcsname{#1}
    \expandafter\gdef\csname @author@last\arabic{authors@count}\endcsname{#2}
}

\newcounter{i}
\def\authorsliststring{}
\def\Al{@author@last}
\def\Af{@author@first}
\let\z\expandafter
\def\authorslist{%
    \whiledo{\value{i} < \value{authors@count}}{%
        \stepcounter{i}%
        \edef\Thei{\thei}%
%        \@nameuse{\Al\thei}\space% for test only
%        \initial{\@nameuse{\Af\thei}}.% for test only
        \z\z\z\g@addto@macro\z\z\z\authorsliststring\z\z\z{\z\z\z%
            \@nameuse\z\z\z{\z\z\z\Al\z\Thei\z}\z\ \z 
            \initial\z{\z\@nameuse\z{\z\Af\Thei}}.}%
        \ifthenelse{\thei = \theauthors@count}{}
            {%,\space% for test only
                \g@addto@macro\authorsliststring{, }%
        }%
    }
}

\newcommand\writetoc{
    \newoutputstream{txt}
    \openoutputfile{\jobname.txt}{txt}
    \addtostream{txt}{\authorsliststring}
    \closeoutputstream{txt}
}

\makeatother

\begin{document}

\authors{Alex}{Andersson}
\authors{Barbara}{Brown}
\authors{Charles}{Chaplin}

\authorslist

\authorsliststring

\writetoc

\end{document}

在此处输入图片描述

相关内容