我想看看如何展示使用可扩展命令的优势。我制作了该命令\myDimensionCommand
,但我认为这不是展示使用完全可扩展命令的优势的最佳方式。
\documentclass{article}
\ExplSyntaxOff
\NewExpandableDocumentCommand {\convertto} {omm}
{
% #1 = number of decimal digits
% #2 = length
% #3 = new unit
\IfNoValueTF {#1}
{
\fpeval{\dimeval{#2}/(1#3)}\,#3
}
{
\fpeval{round(\dimeval{#2}/(1#3),#1)}\,#3
}
}
% Define a command that uses \convertto
\NewDocumentCommand{\myDimensionCommand}{m m}
{
The~converted~dimension~is:~\convertto{#1}{#2}{mm}.
}
\ExplSyntaxOff
\begin{document}
\convertto[2]{34pt}{cm}
\end{document}
答案1
例如,可以在书签中显示差异:
\documentclass{article}
\ExplSyntaxOff
\NewExpandableDocumentCommand {\convertto} {omm}
{
% #1 = number of decimal digits
% #2 = length
% #3 = new unit
\IfNoValueTF {#1}
{
\fpeval{\dimeval{#2}/(1#3)}\,#3
}
{
\fpeval{round(\dimeval{#2}/(1#3),#1)}\,#3
}
}
\NewDocumentCommand {\xconvertto} {omm}
{
% #1 = number of decimal digits
% #2 = length
% #3 = new unit
\IfNoValueTF {#1}
{
\fpeval{\dimeval{#2}/(1#3)}\,#3
}
{
\fpeval{round(\dimeval{#2}/(1#3),#1)}\,#3
}
}
\ExplSyntaxOff
\usepackage{hyperref}
\begin{document}
\section{ Test: \convertto[2]{34pt}{cm}}
\section{ Test: \xconvertto[2]{34pt}{cm}}
\end{document}
这将打印相同的内容:
但书签看起来却截然不同:
答案2
区别在于一个是可扩展的,另一个不是,因此,例如\edef
,一个是完全扩展的,另一个不是,您可以在其他表达式中使用可扩展的命令,而不能在那里使用不可扩展的命令。因此,一个更容易嵌套在其他代码中,另一个需要您设置一个宏,将结果作为代码的一部分,以便其他代码可以使用该宏对结果执行其他步骤。简单文档说明了 中行为的差异\edef
:
\documentclass{article}
\ExplSyntaxOn
\NewExpandableDocumentCommand \convertto { o m m }
{
% #1 = number of decimal digits
% #2 = length
% #3 = new unit
\IfNoValueTF {#1}
{ \fpeval{\dimeval{#2}/(1#3)}\,#3 }
{ \fpeval{round(\dimeval{#2}/(1#3),#1)}\,#3 }
}
\NewDocumentCommand \protectedconvertto { o m m }
{
% #1 = number of decimal digits
% #2 = length
% #3 = new unit
\IfNoValueTF {#1}
{ \fpeval{\dimeval{#2}/(1#3)}\,#3 }
{ \fpeval{round(\dimeval{#2}/(1#3),#1)}\,#3 }
}
\ExplSyntaxOff
\begin{document}
\ttfamily
\edef\foo{\convertto{2cm}{mm}}\meaning\foo
\edef\foo{\protectedconvertto{2cm}{mm}}\meaning\foo
\end{document}
答案3
这其实不是优点和缺点的问题,因为只有你才能选择一个合适的定义。还要注意的是,你在定义中添加了大量行尾空格,因为你缺少\ExplSyntaxOn
在这里,我在受保护的命令中使用您的定义,就像您拥有的那样,并将其作为可扩展的命令,然后在扩展上下文中使用它们(\typeout
)您得到
\myDimensionCommandA {34pt}{cm}
The converted dimension is: 1.194963331949633\,cm{mm}.
因此哪个命令有利取决于您在真实环境中需要哪个输出。
\documentclass{article}
\ExplSyntaxOn% ON!!!!!
\NewExpandableDocumentCommand {\convertto} {omm}
{
% #1 = number of decimal digits
% #2 = length
% #3 = new unit
\IfNoValueTF {#1}
{
\fpeval{\dimeval{#2}/(1#3)}\,#3
}
{
\fpeval{round(\dimeval{#2}/(1#3),#1)}\,#3
}
}
% Define a protected command that uses \convertto
\NewDocumentCommand{\myDimensionCommandA}{m m}
{
The~converted~dimension~is:~\convertto{#1}{#2}{mm}.
}
% Define an expandable command that uses \convertto
\NewExpandableDocumentCommand{\myDimensionCommandB}{m m}
{
The~converted~dimension~is:~\convertto{#1}{#2}{mm}.
}
\ExplSyntaxOff
\begin{document}
\typeout{\myDimensionCommandA{34pt}{cm}}
\typeout{\myDimensionCommandB{34pt}{cm}}
\end{document}
请注意,这里的第二个看起来可能更具可读性,但它仅显示了其内部定义的一部分,\,
其他命令可能会显示更多您永远不想在这样的上下文中显示的内部实现细节,因此选择使用哪种样式取决于命令和可能使用它的上下文。
答案4
可扩展性有用的另一个场景是创建外部文本文件,例如,保存数据库内容的逗号分隔值列表/.csv 文件,这些文件将由不理解 LaTeX 语法的 TeX 以外的程序处理,以便要写入外部文本文件的内容中的所有控制序列标记都应通过扩展消失。
以下示例通过包 datatool 生成两个 .csv 文件。
\verbatiminput
(包中的命令逐字用于让您可以在编译后的 pdf 文件中看到这些文件的内容。
这些文件中的第二个来自使用不可扩展命令的条目,因此它包含\myDimensionCommand {2}{2.54cm}
您可能不想要的 .csv 文件中的内容,该文件将由 LaTeX 以外的软件进一步处理。
\documentclass{article}
\usepackage{datatool, verbatim}
% \ExplSyntaxOn
% \cs_new_eq:NN \fpeval \fp_eval:n
% \cs_new_eq:NN \dimeval \dim_eval:n
% \ExplSyntaxOff
\NewExpandableDocumentCommand {\convertto} {omm}
{%%
% #1 = number of decimal digits
% #2 = length
% #3 = new unit
\IfNoValueTF {#1}
{%%
\fpeval{\dimeval{#2}/(1#3)}\,#3%%
}
{%%
\fpeval{round(\dimeval{#2}/(1#3),#1)}\,#3%%
}%%
}
% Define a command that uses \convertto
\NewDocumentCommand{\myDimensionCommand}{m m}
{%% The first argument of \convertto is optional and therefore
%% must be in square brackets!!!
The converted dimension is: \convertto[{#1}]{#2}{mm}.%%
}
% Create .csv-files holding values of length quantities
% expressed as multiples of different units:
\begingroup
\def\,{}% \convertto beneath other things delivers a
% control symbol token \, , which in turn in LaTeX
% is defined as a protected/an unexpandable command
% for producing a thin horizontal space (.16667em).
% We want neither a thinspace nor the control sequence
% \, to be written to text files, thus within a local
% scope/a group redefine \, so that it just vanishes
% when being expanded.
\DTLnewdb{Database}%
\DTLaddcolumn{Database}{ValueToConvert}%
\DTLsetheader{Database}{ValueToConvert}{dimension to convert}%
\DTLaddcolumn{Database}{ConversionResults}%
\DTLsetheader{Database}{ConversionResults}{result of conversion}%
\dtlexpandnewvalue
\DTLnewrow{Database}%
\DTLnewdbentry{Database}{ValueToConvert}{2.54cm}%
\DTLnewdbentry{Database}{ConversionResults}{\convertto[2]{2.54cm}{in}}%
\DTLnewrow{Database}%
\DTLnewdbentry{Database}{ValueToConvert}{65536sp}%
\DTLnewdbentry{Database}{ConversionResults}{\convertto[2]{65536sp}{pt}}%
\dtlnoexpandnewvalue
\DTLsavedb{Database}{Entriesxpanded.csv}%
\DTLcleardb{Database}%
\DTLaddcolumn{Database}{ValueToConvert}%
\DTLsetheader{Database}{ValueToConvert}{dimension to convert}%
\DTLaddcolumn{Database}{ConversionResults}%
\DTLsetheader{Database}{ConversionResults}{result of conversion}%
\dtlexpandnewvalue
\DTLnewrow{Database}%
\DTLnewdbentry{Database}{ValueToConvert}{2.54cm}%
\DTLnewdbentry{Database}{ConversionResults}{\myDimensionCommand{2}{2.54cm}}%
\DTLnewrow{Database}%
\DTLnewdbentry{Database}{ValueToConvert}{72bp}%
\DTLnewdbentry{Database}{ConversionResults}{\myDimensionCommand{2}{72bp}}%
\dtlnoexpandnewvalue
\DTLsavedb{Database}{Entriesunexpanded.csv}%
\DTLcleardb{Database}%
\endgroup
\begin{document}
% The content of the .csv-files
Here is the content of the file "Entriesxpanded.csv" which holds entries coming from expandable commands:
\verbatiminput{Entriesxpanded.csv}
Here is the content of the file "Entriesunexpanded.csv" which holds entries coming from unexpandable commands:
\verbatiminput{Entriesunexpanded.csv}
\end{document}