我希望定义一些技术要求,以及它们如此的原因。
我想要类似的东西:
\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:NNn
zref-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}
(这两种方法的一个值得注意的区别是,第二种方法为相同的⟨范围⟩多次产生关于多重定义标签的错误消息,而第一种方法则会默默使用最后提供的值。)