我正在尝试创建 2 个宏来模拟 Java 中的数组列表。我正在使用xstring StrSubstitute为此,但我遇到了一个问题。下面是代码,它有点长,因为它包含宏和测试文档。
当前活动的 StrSubstitute 行正在工作,因为它明确指定了替换的接收者(\Cities
)。
\csname #1\endcsname
另一方面,第一行注释掉的 StrSubstitute 行(使用)导致以下 TeX 错误:
! Extra \endcsname.
<argument> \csname testAL\endcsname
l.21 \addElementToArrayList{testAL}{Paris}
第二行注释(仅使用#1
)导致以下错误:
! Missing control sequence inserted.
<inserted text>
\inaccessible
l.21 \addElementToArrayList{testAL}{Paris}
我尝试阅读一些TeX资源,但无法使其工作,并且发现了很多可能性(\def
,,...)\edef
\noexpand
\documentclass[a4paper,10pt]{article}
\usepackage[utf8x]{inputenc}
\RequirePackage{xstring} %will use this package for the internal list structure
\def\ARRAYENDSENTINEL{@@} %indicates array end
\def\ARRAYSEPARATOR{,} %element separator
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Macro to create a new list:
%Parameters: <list name>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\def\newArrayList#1{%
\expandafter\def\csname#1\endcsname{\ARRAYENDSENTINEL}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Macro to append element on a list:
%Parameters: <list name>, <element to add>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\def\addElementToArrayList#1#2{
\StrSubstitute[1]{\csname #1\endcsname}{\ARRAYENDSENTINEL}{\ARRAYSEPARATOR #2\ARRAYENDSENTINEL}[\Cities] %working
%\StrSubstitute[1]{\csname #1\endcsname}{\ARRAYENDSENTINEL}{\ARRAYSEPARATOR #2\ARRAYENDSENTINEL}[\csname #1\endcsname] %NOT working!
%\StrSubstitute[1]{\csname #1\endcsname}{\ARRAYENDSENTINEL}{\ARRAYSEPARATOR #2\ARRAYENDSENTINEL}[#1] %NOT working either!
}
%opening
\title{Testing ArrayList}
\author{}
\begin{document}
\maketitle
\newArrayList{Cities}
Contents of Cities: \textbf{[\Cities]}
\addElementToArrayList{Cities}{Paris}
Contents of Cities: \textbf{[\Cities]}
\addElementToArrayList{Cities}{London}
Contents of Cities: \textbf{[\Cities]}
\addElementToArrayList{Cities}{Rome}
Contents of Cities: \textbf{[\Cities]}
\end{document}
答案1
您不能在需要的\csname foo\endcsname
位置使用,例如将重新定义为参数文本和替换文本。您需要先扩展一次才能构建。原语在这里可以帮助您。它会在以下标记后扩展标记(=~ 宏或字符)一次。因此将扩展为,以便定义。这里的一个问题是,如果您想在长行的末尾扩展,则可能需要多次。\foo
\def\csname foo\endcsname{...}
\csname
foo\endcsname
...
\csname foo\endcsname
\foo
\expandafter
\expandafter\def\csname foo\endcsname{...}
\def\foo{...}
\foo
\expandafter
\csname ...\endcsname
在这种情况下,最好将该行存储在临时宏中:
\def\addElementToArrayList#1#2{%
\begingroup
\def\temp{\endgroup\StrSubstitute[1]{\csname #1\endcsname}{\ARRAYENDSENTINEL}{\ARRAYSEPARATOR #2\ARRAYENDSENTINEL}[}%
\expandafter\temp\csname #1\endcsname]%
}
或者扩展\csname ...\endcsname
第一个宏并将其提供给第二个宏:
\def\addElementToArrayList#1{%
\expandafter\addElementToArrayListX\expandafter{\csname #1\endcsname}%
}
\def\addElementToArrayListX#1#2{%
\StrSubstitute[1]{#1}{\ARRAYENDSENTINEL}{\ARRAYSEPARATOR #2\ARRAYENDSENTINEL}[#1]%
}
这里我们\expandafter
连续使用两个 s 来“跳过”\addElementToArrayListX
和{
。请注意,仅使用第二个宏读取第二个参数是完全可以的。