将计算结果自动存储在新的宏名下

将计算结果自动存储在新的宏名下

由于我现在通过宏访问表中的值,以便在文本中进行动态引用(请参阅这里) 并使用它进行计算,我需要一种方法来使存储值的结果变量更加用户友好。由于 LaTeX 的限制,不允许在宏名称中使用数字或任何分隔符(而我有很多宏),我使用\csname\dots\endcsnameTeX FAQ 中的“ ”方法来创建更有意义的名称。

这会导致以下复杂情况,如下面的 MWE 所示:我使用通过或siunitx打印数字。由于这些命令仅接受数字,因此我无法在其中进行计算。我使用进行计算并将结果存储在(临时)名称下。这导致每个变量都有两行代码:\num\SIl3fp

\calc{\Numtest}{500/2}% store result
\DefineRemark{num:test}{\Numtest}% label result

在文本中,结果将被称为\num{\Remark{num:test}}。我想将两个命令合并为一个命令,如下所示\newcalc{<varname>}{<calculation>}。以下不起作用,因为\temp不会被覆盖。我需要为每个 实例指定一个新的随机名称\newcalc

\newcommand{\newcalc}[2]{%
\calc{\temp}{#2}
\DefineRemark{#1}{\temp}
}

有什么方法可以解决这个问题?在 MWE 中的另一个注释中,我基于\num\SI合并了\Remark宏创建了两个新命令。通过完全复制原始定义来创建这些命令是个好主意吗?

\documentclass{scrartcl}

\usepackage{siunitx,xparse,expl3}

% simple calculation command that stores the result
\ExplSyntaxOn
\NewDocumentCommand {\calc} { m m } {
  \tl_set:Nx #1 { \fp_to_tl:n {#2} }
}
\ExplSyntaxOff

% Workaround for non-letters in macro names
\newcommand{\DefineRemark}[2]{%
  \expandafter\newcommand\csname rmk-#1\endcsname{#2}%
}
\newcommand{\Remark}[1]{\csname rmk-#1\endcsname}

% Create \Num and \NUM based on siunitx' \num and \SI to incorporate the above directly
% (so \Num is \num{\remark{.}}). Not sure if it as a good idea to do it that way
\ExplSyntaxOn
\NewDocumentCommand \Num { o m } {
  \leavevmode
  \group_begin:
    \IfNoValueF {#1}
      { \keys_set:nn { siunitx } {#1} }
    \__siunitx_number_output:n {\Remark{#2}}
  \group_end:
}
\NewDocumentCommand \NUM { o m o m } {
  \leavevmode
  \group_begin:
    \IfNoValueTF {#1}
      { \__siunitx_combined:nnnn { } {\Remark{#2}} {#3} {#4} }
      {
        \keys_set:nn { siunitx } {#1}
        \__siunitx_combined:nnnn {#1} {\Remark{#2}} {#3} {#4}
      }
  \group_end:
}
\ExplSyntaxOff

% Test if \Num and \NUM Works
\calc{\Numtest}{500/2}
\DefineRemark{num:test}{\Numtest}

% Trying to combine \calc and \DefineRemark
% This does not work :( Would need to create a new "\temp" each time
\newcommand{\newcalc}[2]{%
\calc{\temp}{#2}
\DefineRemark{#1}{\temp}
}

\newcalc{new:calc1}{250/2}
\newcalc{new:calc2}{125/2}


\begin{document}

Test Num and NUM Macros: \Num{num:test} and \NUM{num:test}{\percent}

\vspace{2ex}

Test the combination of calc and DefineRemark. The two values should be
different: \Num{new:calc1} and \Num{new:calc2}

\end{document}

答案1

我建议采取一种截然不同的方法:

\documentclass{scrartcl}

\usepackage{siunitx,xparse,expl3}

% simple calculation command that stores the result
\ExplSyntaxOn
\NewDocumentCommand{\calc}{ m m }
 {
  \tl_set:cx { l_jorg_rmk_#1_tl } { \fp_to_tl:n { #2 } }
 }
\NewDocumentCommand{\usekey}{ m }
 {
  \tl_use:c { l_jorg_rmk_#1_tl }
 }
% Create \Num and \NUM based on siunitx' \num and \SI to incorporate the above directly
% (so \Num is \num{\remark{.}}). Not sure if it as a good idea to do it that way
\NewDocumentCommand \Num { o m }
 {
  \leavevmode
  \group_begin:
    \IfNoValueF {#1}
      { \keys_set:nn { siunitx } {#1} }
    \__siunitx_number_output:n {\tl_use:c { l_jorg_rmk_#2_tl } }
  \group_end:
}
\NewDocumentCommand \NUM { o m o m }
 {
  \leavevmode
  \group_begin:
    \IfNoValueTF {#1}
      { \__siunitx_combined:nnnn { } { \tl_use:c { l_jorg_rmk_#2_tl } } {#3} {#4} }
      {
        \keys_set:nn { siunitx } {#1}
        \__siunitx_combined:nnnn {#1} { \tl_use:c { l_jorg_rmk_#2_tl } } {#3} {#4}
      }
  \group_end:
}
\ExplSyntaxOff

% Test if \Num and \NUM Works
\calc{num:test}{500/2}
\calc{new:calc1}{250/2}
\calc{new:calc2}{125/2}


\begin{document}

Test Num and NUM Macros: \Num{num:test} and \NUM{num:test}{\percent}

\vspace{2ex}

Test the combination of calc and DefineRemark. The two values should be
different: \Num{new:calc1} and \Num{new:calc2}

\vspace{2ex}

Here's a key used by itself: \usekey{num:test}

\end{document}

但是,使用\__siunitx_number_output:n\__siunitx_combined:nnnn是一种不恰当的处理方式,因为这些命令以__哪个为前缀使得它们成为“内部”的,因此必然会在未经通知的情况下进行更改(感谢 Bruno Le Floch 对此的评论)。

在我看来siunitx 应该为内部命令提供公共接口,但目前以这种方式使用命令存在很多风险。因此,更好的建议是将\Num和的定义更改\NUM为如下

\NewDocumentCommand{\Num} { o m }
 {
   \num [ #1 ] { \tl_use:c { l_jorg_rmk_#2_tl } }
 }

\NewDocumentCommand{\NUM} { o m o m }
 {
  \SI [ #1 ] { \tl_use:c { l_jorg_rmk_#2_tl } } [ #3 ] { #4 }
 }

\SI这更简单。和的调用\num应该自己考虑\IfNoValue...业务。

相关内容