如何定义多参数常量

如何定义多参数常量

我希望定义一些技术要求,以及它们如此的原因。

我想要类似的东西:

\newcounter{techreq}
\newcommand{\techreq}{\refstepcounter{techreq}\arabic{techreq}}
\newreq{
label=apple;
nb=\techreq;
def={This is my first requirement};
reason={It is like because I said so};
}

然后,理想情况下使用它,例如:

This is my TR\req{apple}.nb, stating that \req{apple}.def, because \req{apple}.reason.

多谢 !

答案1

语法必须略有不同,因为它实际上不是在句点后添加属性名称的 LaTeX。

\documentclass{article}
%\usepackage{xparse} % uncomment if using LaTeX with a version prior to 2020-10-01

\ExplSyntaxOn

\NewDocumentCommand{\newreq}{mm}
 {
  \huberland_req_new:nn { #1 } { #2 }
 }
\NewExpandableDocumentCommand{\req}{mm}
 {
  \prop_item:cn { g_huberland_req_#1_prop } { #2 }
 }

\int_new:N \g_huberland_req_nb_int

\cs_new_protected:Nn \huberland_req_new:nn
 {
  \prop_gclear_new:c { g_huberland_req_#1_prop }
  \prop_gset_from_keyval:cn { g_huberland_req_#1_prop } { #2 }
  \int_gincr:N \g_huberland_req_nb_int
  \prop_gput:cnx { g_huberland_req_#1_prop }
   { nb }
   { \int_to_arabic:n { \g_huberland_req_nb_int } }
 }

\ExplSyntaxOff

\newreq{apple}{
  def={This is my first requirement},
  reason={It is like because I said so},
}

\begin{document}

This is my TR\req{apple}{nb}, stating that \req{apple}{def},
because \req{apple}{reason}.

\end{document}

标签最好在 中设置为单独的参数\newreq。第二个参数可以是任何键值列表。数字是自动分配的。

在此处输入图片描述

实际上,使用最新的 LaTeX 版本 ( L3 programming layer <2020-12-07>),可以根据您的喜好获得语法。

\documentclass{article}
%\usepackage{xparse} % uncomment if using LaTeX with a version prior to 2020-10-01

\ExplSyntaxOn

\NewDocumentCommand{\newreq}{mm}
 {
  \huberland_req_new:nn { #1 } { #2 }
 }
\NewDocumentCommand{\req}{m}
 {
  \tl_set:Nn \l__huberland_req_label_tl { #1 }
  \__huberland_req_get:w
 }

\int_new:N \g_huberland_req_nb_int
\tl_new:N \l__huberland_req_label_tl

\cs_new_protected:Nn \huberland_req_new:nn
 {
  \prop_gclear_new:c { g_huberland_req_#1_prop }
  \prop_gset_from_keyval:cn { g_huberland_req_#1_prop } { #2 }
  \int_gincr:N \g_huberland_req_nb_int
  \prop_gput:cnx { g_huberland_req_#1_prop }
   { nb }
   { \int_to_arabic:n { \g_huberland_req_nb_int } }
 }

\cs_new_protected:Npn \__huberland_req_get:w
 {
  \peek_regex_replace_once:nn { \.([a-z]*) } { \c{__huberland_req_prop:n}\cB\{\1\cE\} }
 }

\cs_new:Nn \__huberland_req_prop:n
 {
  \prop_item:cn { g_huberland_req_ \l__huberland_req_label_tl _prop } { #1 }
 }

\ExplSyntaxOff

\newreq{apple}{
  def={This is my first requirement},
  reason={It is like because I said so},
}

\begin{document}

This is my TR\req{apple}.nb stating that \req{apple}.def,
because \req{apple}.reason.

\end{document}

使用此代码,仅允许使用名称仅由小写字母组成的属性,但更改正则表达式以允许其他字符并不困难。

答案2

使用expl3 的\keyval_parse:NNn参考值-package 宏

\DefineMultiParameterConstant{⟨name of constant⟩}{%
  ⟨comma-separated ⟨parameter⟩=⟨value⟩-list⟩
}%

\ReferMultiParameterConstant{⟨name of constant⟩}{⟨parameter⟩}

可以被定义。

(您可以轻松地将它们重命名为\newreq相应的\req。)

\ReferNewMultiParameterConstant/的语法与您的 规范\req不符:
⟨范围⟩没有用点分隔,而是形成一个非可选的未限定的第二个宏参数。

一种方法是使用\keyval_parse:NNnzref-property-list 中常量的所有参数的累积值,然后执行以下操作\zref@labelbylist

\errorcontextlines=10000
\documentclass{article}
\usepackage{xparse, zref}

\makeatletter
\ExplSyntaxOn
\zref@newlist{MultiParameterConstantPropertylist}
\NewDocumentCommand\DefineMultiParameterConstant{mm}{
  \@bsphack
  \group_begin:
  \keyval_parse:NNn \DefineMultiParameterConstant_SetProperty:n \DefineMultiParameterConstant_SetProperty:nn {#2}
  \zref@wrapper@immediate {
    \zref@labelbylist{#1}{MultiParameterConstantPropertylist}
  }
  \group_end:
  \@esphack
}
\NewDocumentCommand\ReferMultiParameterConstant{mm}{
  \zifrefundefined{#1}{\nfss@text{\reset@font\bfseries??}}{
    \zref@ifrefcontainsprop{#1}{MultiParameterConstant@#2}{
       \zref@ifpropundefined{MultiParameterConstant@#2}{\zref@newprop{MultiParameterConstant@#2}{}}{}
       \zref@extractdefault{#1}{MultiParameterConstant@#2}{
         \zref@refused{#1}\nfss@text{\reset@font\bfseries??}
       }
    }{
      \protect\G@refundefinedtrue
      \@latex@warning{
         Reference~‘#1’~on~page~\thepage \space does~not~have~property~‘#2’
      }
      \nfss@text{\reset@font\bfseries??}
    }
  }
}
\cs_new:Nn \DefineMultiParameterConstant_SetProperty:n { 
  \DefineMultiParameterConstant_SetProperty:nn {#1}{}
}
\cs_new:Nn \DefineMultiParameterConstant_SetProperty:nn {
   \zref@ifpropundefined{MultiParameterConstant@#1}{\zref@newprop{MultiParameterConstant@#1}{}}{}
   \zref@iflistcontainsprop{MultiParameterConstantPropertylist}{MultiParameterConstant@#1}{}{
     \zref@localaddprop{MultiParameterConstantPropertylist}{MultiParameterConstant@#1}
   }
   \zref@setcurrent{MultiParameterConstant@#1}{\unexpanded{#2}}
} 
\ExplSyntaxOff
\makeatother

\parskip=\medskipamount
\parindent=0ex

\begin{document}

\def\SomeMacro{Definition of \texttt{\unexpanded{\string\SomeMacro}} current at the time of referencing MyFirstConstant before creating label.}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterA}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterA}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterB}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterB}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterC}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterC}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterD}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterD}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterE}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterE}

\verb|\ReferMultiParameterConstant{MySecondConstant}{foo}|:\\
\ReferMultiParameterConstant{MySecondConstant}{foo}

\verb|\ReferMultiParameterConstant{MySecondConstant}{bar}|:\\
\ReferMultiParameterConstant{MySecondConstant}{bar}

\verb|\ReferMultiParameterConstant{MySecondConstant}{baz}|:\\
\ReferMultiParameterConstant{MySecondConstant}{baz}

Some text.

\def\SomeMacro{Definition of \texttt{\unexpanded{\string\SomeMacro}} current at the time of creating reference to MyFirstConstant.}

\DefineMultiParameterConstant{MyFirstConstant}{%
  ParameterA=This is the value of MyFirstConstant's parameter A,
  ParameterB=This is the value of MyFirstConstant's parameter B,
  ParameterC=\SomeMacro,              % \SomeMacro will be expanded while writing the label to .aux-file.
                                      % Thus referencing ParameterC yields "Right before creating label".
  ParameterD=\unexpanded{\SomeMacro}, % \SomeMacro will not be expanded while writing the label to .aux-file.
                                      % Thus referencing ParameterD yields "\SomeMacro".
                                      % What you get depends on the definition of \SomeMacro current at the time of referencing.
  ParameterE=\protect\SomeMacro,      % \SomeMacro will not be expanded while writing the label to .aux-file.
                                      % Thus referencing ParameterE yields "\protect\SomeMacro".
                                      % What you get depends both on the state of \protect and on the definition of
                                      % \SomeMacro current at the time of referencing.
}%

Some text.

\DefineMultiParameterConstant{MySecondConstant}{%
  foo=This is the value of MySecondConstant's parameter foo,
  bar=This is the value of MySecondConstant's parameter bar,
  baz=This is the value of MySecondConstant's parameter baz,
}%

\def\SomeMacro{Definition of \texttt{\unexpanded{\string\SomeMacro}} current at the time of referencing MyFirstConstant after creating label.}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterA}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterA}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterB}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterB}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterC}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterC}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterD}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterD}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterE}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterE}

\verb|\ReferMultiParameterConstant{MySecondConstant}{foo}|:\\
\ReferMultiParameterConstant{MySecondConstant}{foo}

\verb|\ReferMultiParameterConstant{MySecondConstant}{bar}|:\\
\ReferMultiParameterConstant{MySecondConstant}{bar}

\verb|\ReferMultiParameterConstant{MySecondConstant}{baz}|:\\
\ReferMultiParameterConstant{MySecondConstant}{baz}


\end{document}

在此处输入图片描述

另一种方法可能是为每个⟨常量的名称⟩-⟨范围⟩-一对:

\errorcontextlines=10000
\documentclass{article}
\usepackage{xparse, zref}

\makeatletter
\ExplSyntaxOn
\zref@newprop{MultiParameterConstantValue}{}
\cs_new:Nn \DefineMultiParameterConstant_SetProperty:n { 
  \DefineMultiParameterConstant_SetProperty:nn {#1}{}
}
\cs_new:Nn \DefineMultiParameterConstant_SetProperty:nn {}
\NewDocumentCommand\DefineMultiParameterConstant{mm}{
  \@bsphack
  \group_begin:
  % !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  % If \keyval_parse:NNn would let you use "functions" which process more
  % than one/two arguments whereof only the last one/the last two were to
  % be passed by \keyval_parse:NNn, then there would not be the inefficient
  % need of (re)defining \DefineMultiParameterConstant_SetProperty:nn
  % again and again.
  % !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  \cs_set:Nn\DefineMultiParameterConstant_SetProperty:nn{
    \zref@wrapper@immediate {
      \zref@setcurrent{MultiParameterConstantValue}{\unexpanded{##2}}
      \zref@labelbyprops{MultiParameterConstant.#1.##1}{MultiParameterConstantValue}
    }
  }
  \keyval_parse:NNn \DefineMultiParameterConstant_SetProperty:n \DefineMultiParameterConstant_SetProperty:nn {#2}
  \group_end:
  \@esphack
}
\NewDocumentCommand\ReferMultiParameterConstant{mm}{
  \zifrefundefined{MultiParameterConstant.#1.#2}{\nfss@text{\reset@font\bfseries??}}{
    \zref@ifrefcontainsprop{MultiParameterConstant.#1.#2}{MultiParameterConstantValue}{
       \zref@extractdefault{MultiParameterConstant.#1.#2}{MultiParameterConstantValue}{
         \zref@refused{MultiParameterConstant.#1.#2}\nfss@text{\reset@font\bfseries??}
       }
    }{
      \protect\G@refundefinedtrue
      \@latex@warning{
         Reference~‘MultiParameterConstant.#1.#2’~on~page~\thepage \space seems~not~to~be~a~component~of~a~multi-parameter~constant
      }
      \nfss@text{\reset@font\bfseries??}
    }
  }
}
\ExplSyntaxOff
\makeatother

\parskip=\medskipamount
\parindent=0ex

\begin{document}

\def\SomeMacro{Definition of \texttt{\unexpanded{\string\SomeMacro}} current at the time of referencing MyFirstConstant before creating label.}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterA}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterA}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterB}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterB}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterC}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterC}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterD}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterD}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterE}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterE}

\verb|\ReferMultiParameterConstant{MySecondConstant}{foo}|:\\
\ReferMultiParameterConstant{MySecondConstant}{foo}

\verb|\ReferMultiParameterConstant{MySecondConstant}{bar}|:\\
\ReferMultiParameterConstant{MySecondConstant}{bar}

\verb|\ReferMultiParameterConstant{MySecondConstant}{baz}|:\\
\ReferMultiParameterConstant{MySecondConstant}{baz}

Some text.

\def\SomeMacro{Definition of \texttt{\unexpanded{\string\SomeMacro}} current at the time of creating reference to MyFirstConstant.}

\DefineMultiParameterConstant{MyFirstConstant}{%
  ParameterA=This is the value of MyFirstConstant's parameter A,
  ParameterB=This is the value of MyFirstConstant's parameter B,
  ParameterC=\SomeMacro,              % \SomeMacro will be expanded while writing the label to .aux-file.
                                      % Thus referencing ParameterC yields "Right before creating label".
  ParameterD=\unexpanded{\SomeMacro}, % \SomeMacro will not be expanded while writing the label to .aux-file.
                                      % Thus referencing ParameterD yields "\SomeMacro".
                                      % What you get depends on the definition of \SomeMacro current at the time of referencing.
  ParameterE=\protect\SomeMacro,      % \SomeMacro will not be expanded while writing the label to .aux-file.
                                      % Thus referencing ParameterE yields "\protect\SomeMacro".
                                      % What you get depends both on the state of \protect and on the definition of
                                      % \SomeMacro current at the time of referencing.
}%

Some text.

\DefineMultiParameterConstant{MySecondConstant}{%
  foo=This is the value of MySecondConstant's parameter foo,
  bar=This is the value of MySecondConstant's parameter bar,
  baz=This is the value of MySecondConstant's parameter baz,
}%

\def\SomeMacro{Definition of \texttt{\unexpanded{\string\SomeMacro}} current at the time of referencing MyFirstConstant after creating label.}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterA}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterA}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterB}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterB}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterC}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterC}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterD}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterD}

\verb|\ReferMultiParameterConstant{MyFirstConstant}{ParameterE}|:\\
\ReferMultiParameterConstant{MyFirstConstant}{ParameterE}

\verb|\ReferMultiParameterConstant{MySecondConstant}{foo}|:\\
\ReferMultiParameterConstant{MySecondConstant}{foo}

\verb|\ReferMultiParameterConstant{MySecondConstant}{bar}|:\\
\ReferMultiParameterConstant{MySecondConstant}{bar}

\verb|\ReferMultiParameterConstant{MySecondConstant}{baz}|:\\
\ReferMultiParameterConstant{MySecondConstant}{baz}


\end{document}

在此处输入图片描述

(这两种方法的一个值得注意的区别是,第二种方法为相同的⟨范围⟩多次产生关于多重定义标签的错误消息,而第一种方法则会默默使用最后提供的值。)

相关内容