我在扩展和不扩展宏时遇到了问题\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 数量?。