我有一些部分或代码是用LaTeX2e
方法编写的。我想用LaTeX3
方法重写它,但我不知道该怎么做。更多解释请参见 MWE
\documentclass[]{article}
\usepackage{xparse}
\newcounter{mycounter}
\setcounter{mycounter}{100}
% ======== Common way =======================
\def\daycell#1#2{\csname dc#1#2\endcsname}
\daycell{1}{2}
\expandafter\def\csname dc12\endcsname{\themycounter}
% =========== The LaTeX3 way =======================
\ExplSyntaxOn
\cs_new:Npn \DayCell {#1#2} {\cs:w dc#1#2 \cs_end:} % I have no idea
\ExplSyntaxOff
\begin{document}
\daycell{1}{2}
\end{document}
添加以澄清
\documentclass[]{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new:Npn \sergiokapone_daycell:nn #1 #2
{
\use:c { dc #1 #2 }
}
\cs_new_protected:Npn \sergiokapone_set_daycell:nnn #1 #2 #3
{
\cs_set:cpn { dc #1 #2 } { #3 }
}
\NewDocumentCommand \SetDayCell { mmm }
{
\sergiokapone_set_daycell:nnn { #1 } { #2 } { #3 }
}
\NewExpandableDocumentCommand \DayCell { m m }
{
\sergiokapone_daycell:nn { #1 } { #2 }
}
\DeclareDocumentCommand\Replicate{ m m }{%
\prg_replicate:nn {#1} {#2}
}
\ExplSyntaxOff
\begin{document}
% ======== desired result (it is work) ========
% Temporary commented
%---- Here \SetDayCell{i}{j}{some number}
%\SetDayCell{1}{1}{1}
%\SetDayCell{1}{2}{2}
%\SetDayCell{1}{3}{3}
%\SetDayCell{1}{4}{4}
%\SetDayCell{1}{5}{5}
% I get what I want 1 2 3 4 5
% ======= I want to just replicate example from above ===
% But it work incorrect
\newcounter{C}
\setcounter{C}{1}
\Replicate{5}{
\SetDayCell{1}{\theC}{\theC}
\stepcounter{C}
}
% I get 6 6 6 6 6
% ==== cell's filling ====
\newcounter{var}
\setcounter{var}{1}
\Replicate{5}{
\DayCell{1}{\thevar}
\stepcounter{var}
}
\end{document}
答案1
执行此操作的标准方法是提供\DayCell
使用:c
参数的函数的变体,如果它只是一个应该转换为控制序列的参数。
另请注意,语句中的参数\cs_new:Npn
不允许包含括号(它的语法或多或少与 TeX 的语法相同\def
)。
使用和类似方法创建的内部函数\cs_new:Npn
应始终包含参数类型作为其名称的一部分,因此对于采用两个括号参数的宏,您应该具有诸如的名称\<module>_<name>:nn
,函数应始终遵循该命名方案\<module>_<name>:<args>
。
此外,如果不是绝对必要,您应该使用更高级别的函数将某些东西转换为宏名,因此只有在绝对必要时才使用\cs:w
和\cs:end
,例如,因为 begin 和 end 在两个不同的宏中,否则您应该使用\use:c
。
此外,\cs_new:Npn
和类似的仅应用于内部功能,文档/用户级别功能应使用\NewDocumentCommand
或类似的来定义。
将以上所有内容转化为一些代码:
\documentclass[]{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new:Npn \sergiokapone_daycell:nn #1 #2
{
\use:c { dc #1 #2 }
}
\cs_new_protected:Npn \sergiokapone_set_daycell:nnn #1 #2 #3
{
\cs_set:cpn { dc #1 #2 } { #3 }
}
\NewDocumentCommand \SetDayCell { mmm }
{
\sergiokapone_set_daycell:nnn { #1 } { #2 } { #3 }
}
\NewExpandableDocumentCommand \DayCell { m m }
{
\sergiokapone_daycell:nn { #1 } { #2 }
}
\ExplSyntaxOff
\begin{document}
\SetDayCell{1}{2}{100}
\DayCell{1}{2}
\end{document}
答案2
你的代码有几个问题。我先分析一下“传统”代码。
如果你\expandafter\def\csname dc#1#2\endcsname{\themycounter}
这样做惯于执行 后将得到 100 \daycell{1}{2}
,除非 的值mycounter
在此期间没有改变。您应该使用\edef
。
至于expl3
实施方面,这似乎需要一个属性清单。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\setdaycell}{mmm}
{
\sergio_daycell_set:nne { #1 } { #2 } { #3 }
}
\NewExpandableDocumentCommand{\daycell}{mm}
{
\prop_item:Nn \l_sergio_daycell_prop { #1#2 }
}
\prop_new:N \l_sergio_daycell_prop
\cs_new_protected:Nn \sergio_daycell_set:nnn
{
\prop_put:Nnn \l_sergio_daycell_prop { #1#2 } { #3 }
}
\cs_generate_variant:Nn \sergio_daycell_set:nnn { nne }
\ExplSyntaxOff
\newcounter{mycounter}
\begin{document}
\setcounter{mycounter}{100}
\setdaycell{1}{2}{\themycounter}
\setcounter{mycounter}{42}
\daycell{1}{2}
\end{document}
这将打印 100。
看了你的例子后,很明显你在扩展方面存在一些问题,类似于上面第二段所描述的。
您可以通过在适当的时候强制扩展来实现这一点。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
%%% for the example
\NewDocumentCommand{\replicate}{mm}
{
\prg_replicate:nn { #1 } { #2 }
}
%%%%%%%%
\NewDocumentCommand{\setdaycell}{mmm}
{
\sergio_daycell_set:nne { #1 } { #2 } { #3 }
}
\NewExpandableDocumentCommand{\daycell}{mm}
{
\prop_item:Ne \l_sergio_daycell_prop { #1#2 }
}
\cs_generate_variant:Nn \prop_put:Nnn { Nx }
\cs_generate_variant:Nn \prop_item:Nn { Ne }
\prop_new:N \l_sergio_daycell_prop
\cs_new_protected:Nn \sergio_daycell_set:nnn
{
\prop_put:Nxn \l_sergio_daycell_prop { #1#2 } { #3 }
}
\cs_generate_variant:Nn \sergio_daycell_set:nnn { nne }
\ExplSyntaxOff
\begin{document}
\newcounter{C}
\setcounter{C}{1}
\replicate{5}{%
\setdaycell{1}{\theC}{\theC}%
\stepcounter{C}%
}
% I get 6 6 6 6 6
% ==== cell's filling ====
\newcounter{var}
\setcounter{var}{1}
\replicate{5}{%%
\daycell{1}{\thevar}%
\stepcounter{var} % <- space is wanted
}
\end{document}
这将正确打印“1 2 3 4 5”