用 \csname 定义的宏的扩展

用 \csname 定义的宏的扩展

我在扩展和不扩展宏时遇到了问题\csname。请看以下代码:

% Save content of a macro via \csname
\def\LetCsVar#1#2{\expandafter\let\csname#1\endcsname=#2}% #1=name, #2=definition
% Get the previous saved content of a macro via \csname
\def\GetCsVar#1{\csname#1\endcsname}% #1=name

\def\txt{Hallo\thinspace you}
txt: \meaning\txt\break  % prints: txt: macro:->Hallo\thinspace you

\count1=1
\LetCsVar{test\the\count1}{\txt}

% \txt can change here
\def\txt{Holla}

\def\a{\GetCsVar{test\the\count1}}
a: \meaning\a\break      % prints: a: macro:->\GetCsVar {test\the \count 1}

\edef\b{\GetCsVar{test\the\count1}}
b: \meaning\b\break      % prints: b: macro:->Hallo\kern .16667em you

\toks0=\expandafter{\a}
\edef\c{\the\toks0}
c: \meaning\c\break      % prints: c: macro:->\GetCsVar {test\the \count 1}

我想知道如何做才能获得具有类似-macro\GetCsVar含义的新宏。macro:->Hallo\thinspace you\txt

问题是扩展\GetCsVar\the \count 1和,\csname但不是初始的\thinspace

谢谢你,彼得

编辑:

受到 David Carlisles 的启发,我创建了一个新的宏\GetCsVarEx

\def\GetCsVarExp#1#2%
{%
\expandafter\expandafter\expandafter%
\def%
\expandafter\expandafter\expandafter%
\ax%
\expandafter\expandafter\expandafter%
{\csname#1\endcsname}%
\expandafter\let\csname#2\endcsname=\ax
}

然后我打电话

\GetCsVarExp{test\the\count1}{d}

然后d: \meaning\d打印出我想要的d: macro:->Hallo\thinspace you

它确实有效,但我希望有更简单的方法来填充宏\d。也许没有?

答案1

tokcycle软件包虽然用于其他目的,但内置了扩展基础结构。它将允许\GetCsVarExp更简单的定义,并允许指定级别的扩展。

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tokcycle}
\newcommand\GetCsVarExp[3][]{\cytoks{}%
  \addcytoks[#1]{\csname#2\endcsname}%
  \expandafter\def\csname#3\expandafter\endcsname
    \expandafter{\the\cytoks}}
\begin{document}
% Save content of a macro via \csname
\def\LesVar#1#2{\expandafter\let\csname#1\endcsname=#2}% #1=name, #2=definition
% Get the previous saved content of a macro via \csname
\def\GesVar#1{\csname#1\endcsname}% #1=name

\def\txt{Hallo\thinspace you}
txt: \meaning\txt  % prints: txt: macro:->Hallo\thinspace you

\count1=1
\LesVar{test\the\count1}{\txt}

% \txt can change here
\def\txt{Holla}

\GetCsVarExp{test\the\count1}{A}% 0 EXPANSIONS
A: \meaning\A

\GetCsVarExp[1]{test\the\count1}{B}% 1 EXPANSION
B: \meaning\B

\GetCsVarExp[2]{test\the\count1}{C}% 2 EXPANSIONS
C: \meaning\C

\GetCsVarExp[x]{test\the\count1}{D}% FULLY EXPANDED
D: \meaning\D
\end{document}

在此处输入图片描述

如果需要以 PlainTex 形式提供结果,那没有问题,因为tokcycle那里也提供有 PlainTex 形式:

\input tokcycle.tex
\long\def\GetCsVarExp[#1]#2#3{\cytoks{}%
  \addcytoks[#1]{\csname#2\endcsname}%
  \expandafter\def\csname#3\expandafter\endcsname
    \expandafter{\the\cytoks}}

% Save content of a macro via \csname
\def\LesVar#1#2{\expandafter\let\csname#1\endcsname=#2}% #1=name, #2=definition
% Get the previous saved content of a macro via \csname
\def\GesVar#1{\csname#1\endcsname}% #1=name

\def\txt{Hallo\thinspace you}
txt: {\tt\meaning\txt}  % prints: txt: macro:->Hallo\thinspace you

\count1=1
\LesVar{test\the\count1}{\txt}

% \txt can change here
\def\txt{Holla}

\GetCsVarExp[0]{test\the\count1}{A}% 0 EXPANSIONS
A: {\tt\meaning\A}

\GetCsVarExp[1]{test\the\count1}{B}% 1 EXPANSION
B: {\tt\meaning\B}

\GetCsVarExp[2]{test\the\count1}{C}% 2 EXPANSIONS
C: {\tt\meaning\C}

\GetCsVarExp[x]{test\the\count1}{D}% FULLY EXPANDED
D: {\tt\meaning\D}

\bye

答案2

在此处输入图片描述

你想扩大三倍,所以需要七\expandafter

% Save content of a macro via \csname
\def\LetCsVar#1#2{\expandafter\let\csname#1\endcsname=#2}% #1=name, #2=definition
% Get the previous saved content of a macro via \csname
\def\GetCsVar#1{\csname#1\endcsname}% #1=name

\def\txt{Hallo\thinspace you}
txt: {\tt\meaning\txt}

\count2=1 %even registers for local assignments
\LetCsVar{test\the\count2}{\txt}

% \txt can change here
\def\txt{Holla}
txt: {\tt\meaning\txt}

\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter
\expandafter
\def
\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter
\expandafter
\b
\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter
\expandafter{\GetCsVar{test\the\count2}}

{\tt\meaning\b}

or as a macro

\def\foo#1#2{%
\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter
\expandafter
\def
\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter
\expandafter
#1%
\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter
\expandafter{\GetCsVar{#2}}
}

\foo\abc{test\the\count2}

{\tt\meaning\abc}
\bye

\foo除了参数顺序之外,上面的请求与后面的请求相同,GetCsVarExp因此您可以改用:



\def\GetCsVarExp#1#2%
{%
\expandafter
\def
\csname#2\expandafter\expandafter\expandafter\endcsname
\expandafter\expandafter\expandafter
{\csname#1\endcsname}%
}


\GetCsVarExp{test\the\count2}{d}
  
{\tt\meaning\d}

答案3

我不确定你为什么要陷入如此复杂的境地。如果你想让基础设施重复做这样的事情,这很容易。

\def\LetCsVar#1#2{% #1=name, #2=definition
  \expandafter\let\csname#1\endcsname=#2%
}
\def\LetCsVarCs#1#2{% #1=name, #2=definition
  \expandafter\let\csname#1\expandafter\endcsname\csname#2\endcsname
}
\def\DefVarCs#1#2{% #1=name, #2=definition
  \expandafter\let\expandafter#1\csname#2\endcsname
}

\tt\frenchspacing

\def\txt{Hallo\thinspace you}
txt: \meaning\txt

\count255=1
\LetCsVar{test\the\count255}{\txt}

% \txt can change here
\def\txt{Holla}

\LetCsVarCs{a}{test\the\count255}
a: \meaning\a

\DefVarCs\b{test\the\count255}
b: \meaning\b

\bye

请注意,其\LetCsVarCs作用与您的相同\GetCsVarExp(仅参数的顺序相反)。

在此处输入图片描述

顺便说一句,\break它完全不适合你使用它的地方。

答案4

我想知道如何做才能获得具有类似-macro\GetCsVar含义的新宏。macro:->Hallo\thinspace you\txt

问题是扩展\GetCsVar\the \count 1和,\csname但不是初始的\thinspace

如果您确实想通过扩展来实现,请注意需要触发三个单独扩展步骤,这需要插入 2 k -1; k=3 tokens \expandafter= 7 tokens的序列\expandafter

第一个扩展步骤传递替换文本,其中\GetCsVar参数由从标记流中抓取的参数替换。该替换文本是一个\csname..\endcsname-thingie。

第二个扩展步骤将\csname..\endcsname-thingie 转换为相应的控制序列标记。如果该控制序列标记在当前范围内尚无意义/未定义,则它(仅在当前范围内,即使\globaldefs具有正值)也被赋予原始的含义\relax

第三个扩展步骤 - 如果它是可扩展的 - 提供该控制序列标记的“顶层扩展”。


但我建议避免扩展要“复制”其定义/含义的宏:

  • 在要复制的宏定义的 ⟨替换文本⟩ 包含多个连续哈希值的特殊情况下,保存副本的宏定义的 ⟨替换文本⟩ 可能与保存原始内容的宏定义的 ⟨替换文本⟩ 不同。这是因为在获取替换文本时,由于展开该宏,##宏定义的 ⟨替换文本⟩ 中的两个连续哈希值会折叠成单个哈希值。#

  • 您会丢失有关定义前缀的信息,例如\long(或\protected当使用带有内置扩展保护的 TeX 引擎时)。

您可能还没有听说过这个\expandafter\endcsname\csname技巧...

为了避免需要扩展宏并因此丢失有关定义前缀的信息,并因此面临每次扩展时替换文本中出现的连续哈希的数量减半的情况,我建议仅使用\let,而不使用中间的临时宏分配。

\tt

%----------------------------------------------------------------------
\def\GetCsVarExp#1#2{%
  \expandafter\let\csname#2\expandafter\endcsname\csname#1\endcsname
}%
%----------------------------------------------------------------------
% Save content of a macro via \csname
\def\LetCsVar#1#2{\expandafter\let\csname#1\endcsname=#2}% #1=name, #2=definition
% Get the previous saved content of a macro via \csname
\def\GetCsVar#1{\csname#1\endcsname}% #1=name

\def\txt{Hello\thinspace you}%
txt: \meaning\txt % prints: txt: macro:->Hallo\thinspace you

\count1=1
\LetCsVar{test\the\count1}{\txt}%

% \txt can change here
\def\txt{Holla}%

\GetCsVarExp{test\the\count1}{d}%

d: \meaning\d      % prints: d: macro:->Hallo\thinspace you.

\bye

让我们通过定义一个扩展为一系列哈希的宏来展示差异,并看看在“复制”时定义会发生什么:

%----------------------------------------------------------------------

\tt

\def\GetCsVarExpcoonlight#1#2{%
  \expandafter\expandafter\expandafter\def
  \expandafter\expandafter\expandafter\ax
  \expandafter\expandafter\expandafter{%
    \csname#1\endcsname
  }%
  \expandafter\let\csname#2\endcsname=\ax
}%
%----------------------------------------------------------------------
\def\GetCsVarExpUlrich#1#2{%
  \expandafter\let\csname#2\expandafter\endcsname\csname#1\endcsname
}%
%----------------------------------------------------------------------
% Save content of a macro via \csname
\def\LetCsVar#1#2{\expandafter\let\csname#1\endcsname=#2}% #1=name, #2=definition
% Get the previous saved content of a macro via \csname
\def\GetCsVar#1{\csname#1\endcsname}% #1=name

\def\SomeHashes{Initially there are 16 hashes: ################}%

%----------------------------------------------------------------------

\LetCsVar{SomeHashes0coonlight}{\SomeHashes}%
\expandafter\string\csname SomeHashes0coonlight\endcsname:\hfil\break
\expandafter\meaning\csname SomeHashes0coonlight\endcsname 

%----------------------------------------------------------------------

\GetCsVarExpcoonlight{SomeHashes0coonlight}{SomeHashes1coonlight}%
\expandafter\string\csname SomeHashes1coonlight\endcsname:\hfil\break
\expandafter\meaning\csname SomeHashes1coonlight\endcsname 

\GetCsVarExpcoonlight{SomeHashes1coonlight}{SomeHashes2coonlight}%
\expandafter\string\csname SomeHashes2coonlight\endcsname:\hfil\break
\expandafter\meaning\csname SomeHashes2coonlight\endcsname 

\GetCsVarExpcoonlight{SomeHashes2coonlight}{SomeHashes3coonlight}%
\expandafter\string\csname SomeHashes3coonlight\endcsname:\hfil\break
\expandafter\meaning\csname SomeHashes3coonlight\endcsname 

% This would yield an error as the single hash is taken 
% for s.th. that denotes a parameter in wrong ways (single
% hash not trailed by single digit in range 1..9; no
% parameters declared in the definition's parameter text, thus
% parameters #1 .. #9 may not occur in the replacement text) :

%\GetCsVarExpcoonlight{SomeHashes3coonlight}{SomeHashes4coonlight}%
%\expandafter\string\csname SomeHashes4coonlight\endcsname:\hfil\break
%\expandafter\meaning\csname SomeHashes4coonlight\endcsname 


%----------------------------------------------------------------------

\LetCsVar{SomeHashes0Ulrich}{\SomeHashes}%
\expandafter\string\csname SomeHashes0Ulrich\endcsname:\hfil\break
\expandafter\meaning\csname SomeHashes0Ulrich\endcsname 

%----------------------------------------------------------------------

\GetCsVarExpUlrich{SomeHashes0Ulrich}{SomeHashes1Ulrich}%
\expandafter\string\csname SomeHashes1Ulrich\endcsname:\hfil\break
\expandafter\meaning\csname SomeHashes1Ulrich\endcsname 

\GetCsVarExpUlrich{SomeHashes1Ulrich}{SomeHashes2Ulrich}%
\expandafter\string\csname SomeHashes2Ulrich\endcsname:\hfil\break
\expandafter\meaning\csname SomeHashes2Ulrich\endcsname 

\GetCsVarExpUlrich{SomeHashes2Ulrich}{SomeHashes3Ulrich}%
\expandafter\string\csname SomeHashes3Ulrich\endcsname:\hfil\break
\expandafter\meaning\csname SomeHashes3Ulrich\endcsname 

% This does not yield an error:

\GetCsVarExpUlrich{SomeHashes3Ulrich}{SomeHashes4Ulrich}%
\expandafter\string\csname SomeHashes4Ulrich\endcsname:\hfil\break
\expandafter\meaning\csname SomeHashes4Ulrich\endcsname 

%----------------------------------------------------------------------

\bye

在此处输入图片描述


如果你感兴趣的话:

正如其他问题的答案中所述,使用-notation 您可以使用以下语法#{实现宏:\CsNameToCsToken

\CsNameToCsToken⟨stuff not in braces⟩{⟨NameOfCs⟩}

⟨stuff not in braces⟩\NameOfCs

⟨stuff not in braces⟩可能为空。)

在 plain-TeX 中的定义:

\chardef\stopromannumeral=`\^^00 %
\long\def\CsNameToCsToken#1#{\romannumeral\InnerCsNameToCsToken{#1}}%
\long\def\InnerCsNameToCsToken#1#2{%
  \expandafter\exchange\expandafter{\csname#2\endcsname}{\stopromannumeral#1}%
}%
\long\def\exchange#1#2{#2#1}%

(由于\romannumeral-expansion ,结果是通过触发两个扩展步骤获得的,例如,通过具有两个“命中”,\expandafter需要 2 k -1 的序列;k=2 个标记\expandafter=3 个标记的序列\expandafter。)

使用这样的宏,您就不会受到特定定义命令的约束:

\CsNameToCsToken{foo}\foo  。

\CsNameToCsToken\newcommand{foo}\newcommand\foo  。

\CsNameToCsToken\DeclareRobustCommand{foo}\DeclareRobustCommand\foo  。

\CsNameToCsToken\NewDocumentCommand{foo}\NewDocumentCommand\foo  。

\CsNameToCsToken\global\long\outer\def{foo}\global\long\outer\def\foo  。

\CsNameToCsToken\expandafter{foo}\bar\expandafter\foo\bar  。

\CsNameToCsToken\expandafter\foo{bar}\expandafter\foo\bar  。

\CsNameToCsToken\CsNameToCsToken\expandafter{foo}{bar}\CsNameToCsToken\expandafter\foo{bar}\expandafter\foo\bar  。

\CsNameToCsToken\string{foo}\string\foo  。

\CsNameToCsToken\meaning{foo}\meaning\foo  。

\CsNameToCsToken\let{foo}=\bar\let\foo=\bar  。

\CsNameToCsToken\let\foo={bar}\let\foo=\bar  。

\CsNameToCsToken\CsNameToCsToken\global\let{foo=}{bar}\CsNameToCsToken\global\let\foo={bar}\global\let\foo=\bar  。

\long\def\PassFirstToSecond#1#2{#2{#1}}\def\bar{AAA}
\CsNameToCsToken\PassFirstToSecond{bar}{\CsNameToCsToken\expandafter\def\expandafter{foo}\expandafter}
\PassFirstToSecond\bar{\CsNameToCsToken\expandafter\def\expandafter{foo}\expandafter}
\CsNameToCsToken\expandafter\def\expandafter{foo}\expandafter{\bar}
\expandafter\def\expandafter\foo\expandafter{\bar}
\def\foo{AAA}  。


在您的场景中,您可以这样做:

\tt
%------------------------------------------------------------------------------
\chardef\stopromannumeral=`\^^00 %
\long\def\CsNameToCsToken#1#{\romannumeral\InnerCsNameToCsToken{#1}}%
\long\def\InnerCsNameToCsToken#1#2{%
  \expandafter\exchange\expandafter{\csname#2\endcsname}{\stopromannumeral#1}%
}%
\long\def\exchange#1#2{#2#1}%
%------------------------------------------------------------------------------

\def\txt{Hallo\thinspace you}
txt: \meaning\txt  % prints: txt: macro:->Hallo\thinspace you

\CsNameToCsToken\let{test1}=\txt
test1: \CsNameToCsToken\meaning{test1}% prints: test1: macro:->Hallo\thinspace you

\CsNameToCsToken\CsNameToCsToken\let{test2}={test1}%
test2: \CsNameToCsToken\meaning{test2}% prints: test2: macro:->Hallo\thinspace you

\CsNameToCsToken\let\teeext={test2}%
teeext: \meaning\teeext % prints: teeext: macro:->Hallo\thinspace you

\bye

在此处输入图片描述


在一个评论你说你找不到如何设置所有的\expandafter

您可能对以下问题的答案感兴趣如何知道附加到 csname 宏时的 expandafter 数量?

相关内容