![具有適當的下標和上標以及自訂參數的複合術語表命令](https://rvso.com/image/472719/%E5%85%B7%E6%9C%89%E9%81%A9%E7%95%B6%E7%9A%84%E4%B8%8B%E6%A8%99%E5%92%8C%E4%B8%8A%E6%A8%99%E4%BB%A5%E5%8F%8A%E8%87%AA%E8%A8%82%E5%8F%83%E6%95%B8%E7%9A%84%E8%A4%87%E5%90%88%E8%A1%93%E8%AA%9E%E8%A1%A8%E5%91%BD%E4%BB%A4.png)
我想建立一個有助於組合 gls 符號的巨集。每個複合符號應包含一個主體和(可選)一個上標和下標(它們本身就是 gls 符號,並在不同的下標/上標符號列表中列出)。此外,我想為某些複合符號添加自訂參數。我想實現的一個例子:
以下是我的問題:
- 為了確保將化合物後添加的子/上標添加到“化合物”子/上標中,我需要使用裝飾功能作為
xparse
我定義的巨集的最後兩個參數 (E{^_}{{}{}}
) - 由於我事先不知道透過添加多少個自訂參數,
args=
我不知道裝飾將具有哪個參數編號(即我必須計算參數數量並動態添加參數編號)。
我想出了以下程式碼(不起作用)。我認為這裡的主要問題是正確的擴展,以便在最終定義巨集之前保存裝飾參數編號的變數(\l_compound_supparameter_tl
和)被擴展。\l_compound_subparameter_tl
此外,我只能將逗號分隔的參數規格傳遞給args
.
\documentclass[margin=5mm]{standalone}
\usepackage[symbols]{glossaries}
\newglossaryentry{body}{
type=symbols,
name={body},
symbol={B},
description={A body.}
}
\newglossaryentry{phase}{
type=symbols,
name={phase},
symbol={\alpha},
description={A material phase.}
}
\newglossaryentry{index}{
type=symbols,
name={index},
symbol={i},
description={A body index.}
}
\ExplSyntaxOn
% Define the keys
\keys_define:nn { my/glscompound }{
body .tl_set:N = \l_compound_body_tl,
args .tl_set:N = \l_compound_args_tl,
superscript .tl_set:N = \l_compound_superscript_tl,
superscript .initial:n = {},
subscript .tl_set:N = \l_compound_subscript_tl,
subscript .initial:n = {},
}
\tl_new:N \l_compound_supparameter_tl % stores the macro parameter for superscript (e.g. #3)
\tl_new:N \l_compound_subparameter_tl % stores the macro parameter for subscript (e.g. #4)
\cs_generate_variant:Nn \exp_args:Nnnx { NnVx }
\NewDocumentCommand{\NewGlsCompound}{ m m }{
\tl_clear:N \l_compound_body_tl
\tl_clear:N \l_compound_args_tl
\tl_clear:N \l_compound_superscript_tl
\tl_clear:N \l_compound_subscript_tl
\tl_set:Nn \l_compound_supparameter_tl { # }
\tl_set:Nn \l_compound_subparameter_tl { # }
\keys_set:nn { my/glscompound } { #2 }
% convert tl to sequence of arguments
\seq_set_split:NnV \l_tmpa_seq { , } \l_compound_args_tl
% get the count of the seq to determine the number of custom arguments
\int_set:Nn \l_tmpa_int { \seq_count:N \l_tmpa_seq }
% parameter number of superscript
\int_incr:N \l_tmpa_int
\tl_put_right:NV \l_compound_supparameter_tl \l_tmpa_int
% parameter number of subscript
\int_incr:N \l_tmpa_int
\tl_put_right:NV \l_compound_subparameter_tl \l_tmpa_int
% convert the arument seq to a single tl
\tl_set:No \l_compound_args_tl { \seq_use:Nn \l_tmpa_seq { , } }
% append the sub/superscript arguments
\tl_put_right:Nn \l_compound_args_tl { ~E{^_}{{}{}} }
% Define the new command
\exp_args:NnVx \NewDocumentCommand {#1} \l_compound_args_tl {
\l_compound_body_tl
% superscript
% evaluated during runtime, if an additional superscript as parameter
% '\l_compound_supparameter_tl' is given
\IfValueT{ \l_compound_supparameter_tl }{
% append the custom superscript to the body of the compound superscript
\tl_put_right:Nn \l_compound_superscript_tl { \l_compound_supparameter_tl }
}
% if the body of the superscript is not empty, call the superscript macro
\tl_if_blank:VF \l_compound_superscript_tl { \sp{ \l_compound_superscript_tl } }
% subscript (same as superscript)
\IfValueT{ \l_compound_supparameter_tl }{
\tl_put_right:Nn \l_compound_subscript_tl { \l_compound_supparameter_tl }
}
\tl_if_blank:VF \l_compound_subscript_tl { \sb{ \l_compound_subscript_tl } }
}
}
\ExplSyntaxOff
\NewGlsCompound{\Body}{
body = { \glssymbol{body} },
args = { O{arg1}, O{arg2} }, % this is comma separated list of arguments
superscript = { \glssymbol{phase},#1 },
subscript = { \glssymbol{index},#2 },
}
\begin{document}
\begin{minipage}{.7\textwidth}
\renewcommand{\arraystretch}{1.5}
\begin{tabular}{l l}
\verb+\Body+ &\(\rightarrow \Body\)\\
\verb+\Body^{,a}_{,y}+ &\(\rightarrow \Body^{,a}_{,y}\)\\
\verb+\Body[foo]+ &\(\rightarrow \Body[foo]\)\\
\verb+\Body[foo]^{,x}+ &\(\rightarrow \Body[foo]^{,x}\)\\
\verb+\Body[foo][bar]^{,x}+ &\(\rightarrow \Body[foo][bar]^{,x}\)
\end{tabular}
\end{minipage}
\end{document}
如果您能幫助我解決擴展混亂問題,我將非常感激!
答案1
首先,您需要一個例程來計算 xparse-argument-signature 指定的參數數量。
在下面的範例中,這就是例程
\MYSTUFF_xparse_arg_signature_count:n
。\__cmd_split_signature:n
我是透過抄襲中描述的例程的程式碼來編寫的評論 LaTeX 2ε 來源,檔案 g:ltcmd.dtx 日期:2023-08-19 版本 v1.2a,「1.7.2 顯示指令的定義」部分。此例程
\MYSTUFF_xparse_arg_signature_count:n
採用一個參數,該參數將為 的實例形成 x-parse-argument-signature\NewDocumentCommand
。
兩個擴充步驟之後的例程傳回一個數字標記序列,以十進位表示法表示 x-parse-argument-signature 指定的參數數量。另一個問題是,在定義while有效時,將類別 8(下標)的下劃線 ( ) 放入命令的 -type 參數
_
的修飾規範中,以便 undescore 具有類別代碼 11(字母)。E
\NewGlsCompound
\NewGlsCompound
\ExplSyntaxOn
我可能會這樣做:
%\errorcontextlines=10000
\ExplSyntaxOn
%-------------------------------------------------------------------------------
\cs_new:Nn \MYSTUFF_xparse_arg_signature_count:n
{
\exp:w \exp_after:wN \exp_after:wN \exp_after:wN \exp_end:
\int_eval:n
{
0 \__MYSTUFF_xparse_arg_signature_count_loop:Nw #1
\q_recursion_tail \q_recursion_stop
}
}
\cs_new:Npn \__MYSTUFF_xparse_arg_signature_count_loop:Nw #1
{
\quark_if_recursion_tail_stop:N #1
\tl_if_exist:cTF
{ c_MYSTUFF_xparse_map_arg_type_to_argclass_\tl_to_str:n{#1}_tl }
{
\tl_use:c
{ c_MYSTUFF_xparse_map_arg_type_to_argclass_\tl_to_str:n{#1}_tl }
}
{ +1 \__MYSTUFF_xparse_arg_signature_count_loop:Nw }
}
\cs_set:Npn \__cmd_tmp:w #1 #2
{
\quark_if_nil:nF
{#1}
{
\tl_const:cn { c_MYSTUFF_xparse_map_arg_type_to_argclass_#1_tl } {#2}
\__cmd_tmp:w
}
}
\__cmd_tmp:w
t{\__MYSTUFF_xparse_arg_remove_arg_specification_of_class_delim:w}
r{\__MYSTUFF_xparse_arg_remove_arg_specification_of_class_delims:w}
d{\__MYSTUFF_xparse_arg_remove_arg_specification_of_class_delims:w}
R{\__MYSTUFF_xparse_arg_remove_arg_specification_of_class_delims_opt:w}
D{\__MYSTUFF_xparse_arg_remove_arg_specification_of_class_delims_opt:w}
O{\__MYSTUFF_xparse_arg_remove_arg_specification_of_class_opt:w}
e{\__MYSTUFF_xparse_arg_remove_arg_specification_of_class_e:w}
E{\__MYSTUFF_xparse_arg_remove_arg_specification_of_class_E:w}
+{\__MYSTUFF_xparse_arg_remove_arg_specification_of_class_prefix:w}
!{\__MYSTUFF_xparse_arg_remove_arg_specification_of_class_prefix:w}
>{\__MYSTUFF_xparse_arg_remove_arg_specification_of_class_processor:w}
={\__MYSTUFF_xparse_arg_remove_arg_specification_of_class_processor:w}
\q_nil \q_nil
%------------
\cs_new:Npn \__MYSTUFF_xparse_arg_remove_arg_specification_of_class_delim:w
#1
{ +1 \__MYSTUFF_xparse_arg_signature_count_loop:Nw }
\cs_new:Npn \__MYSTUFF_xparse_arg_remove_arg_specification_of_class_delims:w
#1 #2
{ +1 \__MYSTUFF_xparse_arg_signature_count_loop:Nw }
\cs_new:Npn \__MYSTUFF_xparse_arg_remove_arg_specification_of_class_delims_opt:w
#1 #2 #3
{ +1 \__MYSTUFF_xparse_arg_signature_count_loop:Nw }
\cs_new:Npn \__MYSTUFF_xparse_arg_remove_arg_specification_of_class_opt:w
#1
{ +1 \__MYSTUFF_xparse_arg_signature_count_loop:Nw }
\cs_new:Npn \__MYSTUFF_xparse_arg_remove_arg_specification_of_class_e:w
#1
{ +\tl_count:n{#1} \__MYSTUFF_xparse_arg_signature_count_loop:Nw }
\cs_new:Npn \__MYSTUFF_xparse_arg_remove_arg_specification_of_class_E:w
#1 #2
{ +\tl_count:n{#1} \__MYSTUFF_xparse_arg_signature_count_loop:Nw }
\cs_new:Npn \__MYSTUFF_xparse_arg_remove_arg_specification_of_class_prefix:w
{ \__MYSTUFF_xparse_arg_signature_count_loop:Nw }
\cs_new:Npn \__MYSTUFF_xparse_arg_remove_arg_specification_of_class_processor:w
#1
{ \__MYSTUFF_xparse_arg_signature_count_loop:Nw }
%-------------------------------------------------------------------------------
\cs_if_exist:NF \IfBlankF { \cs_new_eq:NN \IfBlankF \tl_if_blank:nF }
\cs_if_exist:NF \IfBlankT { \cs_new_eq:NN \IfBlankT \tl_if_blank:nT }
\cs_if_exist:NF \IfBlankTF { \cs_new_eq:NN \IfBlankTF \tl_if_blank:nTF }
%-------------------------------------------------------------------------------
\tl_new:N \l_MYSTUFF_GLSCOMPOUND_body_tl
\tl_new:N \l_MYSTUFF_GLSCOMPOUND_args_tl
\tl_new:N \l_MYSTUFF_GLSCOMPOUND_superscript_tl
\tl_new:N \l_MYSTUFF_GLSCOMPOUND_subscript_tl
\tl_new:N \l_MYSTUFF_GLSCOMPOUND_supparameter_tl
\tl_new:N \l_MYSTUFF_GLSCOMPOUND_subparameter_tl
%-------------------------------------------------------------------------------
\keys_define:nn { MYSTUFF/GLSCOMPOUND }{
body.tl_set:N = \l_MYSTUFF_GLSCOMPOUND_body_tl,
args.tl_set:N = \l_MYSTUFF_GLSCOMPOUND_args_tl,
superscript.tl_set:N = \l_MYSTUFF_GLSCOMPOUND_superscript_tl,
subscript.tl_set:N = \l_MYSTUFF_GLSCOMPOUND_subscript_tl,
}
% ------------------------------------------------------------------------------
% Use expl3-infrastructure for providing error-message in case the key
% "body" is not specified in the 2nd argument of \NewGlsCompound.
% ..............................................................................
\prop_gput:Nnn \g_msg_module_type_prop { MYSTUFF_GLSCOMPOUND } {}
\prop_gput:Nnn
\g_msg_module_name_prop
{ MYSTUFF_GLSCOMPOUND }
{Macro-Defined-In-Preamble:}
\msg_new:nnnn {MYSTUFF_GLSCOMPOUND}
{No Value specified}
{Macro~#1:~No~value~for~key~"#3"~specified.}
{In~the~#2~argument~a~value~for~key~"#3"~must~be~specified~%
when~calling~macro~#1.}
\cs_new:Npn \NoValueSpecifiedError #1#2#3 {
\exp_args:Nne \use:nn {
\msg_error:nnnnn {MYSTUFF_GLSCOMPOUND} {No Value specified}
}{{\iow_char:N \\ \cs_to_str:N#1}}{#2}{#3}
}%
%-------------------------------------------------------------------------------
% In order to get _ of category 8(subscript) and ^ of category 7(superscript)
% into the embellishment specification of the E-type argument of the command
% defined via \NewGlsCompound, define a scratch variant of \NewGlsCompound
% which as arguments grabs these tokens and redefines itself.
\group_begin:
\cs_set:Npn \NewGlsCompound #1#2
{
\group_end:
\NewDocumentCommand \NewGlsCompound {mm} {
\group_begin:
\exp_args:Nnx \keys_set:nn { MYSTUFF/GLSCOMPOUND } {
body={\exp_not:o{\c_novalue_tl}},
args={},
superscript={},
subscript={}
}
\keys_set:nn { MYSTUFF/GLSCOMPOUND } { ##2 }
\exp_args:NV \tl_if_novalue:nTF
\l_MYSTUFF_GLSCOMPOUND_body_tl
{ \group_end: \NoValueSpecifiedError{\NewGlsCompound}{second}{body} }
{
\tl_set:Nf \l_MYSTUFF_GLSCOMPOUND_supparameter_tl
{
\int_eval:n
{
\exp_args:No \MYSTUFF_xparse_arg_signature_count:n
{\l_MYSTUFF_GLSCOMPOUND_args_tl} + 1
}
}
\tl_set:Nf \l_MYSTUFF_GLSCOMPOUND_subparameter_tl
{
\int_eval:n
{
\tl_use:N \l_MYSTUFF_GLSCOMPOUND_supparameter_tl + 1
}
}
\tl_put_left:Nn \l_MYSTUFF_GLSCOMPOUND_supparameter_tl {####}
\tl_put_left:Nn \l_MYSTUFF_GLSCOMPOUND_subparameter_tl {####}
\tl_put_right:Nn \l_MYSTUFF_GLSCOMPOUND_args_tl { E{#1#2}{{}{}} }
\__MYSTUFF_GLSCOMPOUND_set_scriptdirective_to_tokenlist:NNN
\l_MYSTUFF_GLSCOMPOUND_superscript_tl
\l_MYSTUFF_GLSCOMPOUND_supparameter_tl
#1
\__MYSTUFF_GLSCOMPOUND_set_scriptdirective_to_tokenlist:NNN
\l_MYSTUFF_GLSCOMPOUND_subscript_tl
\l_MYSTUFF_GLSCOMPOUND_subparameter_tl
#2
\exp_args:Nnx
\use:nn
{ \group_end: \NewDocumentCommand {##1} }
{
{ \exp_not:o{\l_MYSTUFF_GLSCOMPOUND_args_tl} }
{
\exp_not:o{ \l_MYSTUFF_GLSCOMPOUND_body_tl}
\exp_not:o{\l_MYSTUFF_GLSCOMPOUND_superscript_tl}
\exp_not:o{\l_MYSTUFF_GLSCOMPOUND_subscript_tl}
}
}
}
}
}
\char_set_catcode_math_superscript:N \^
\char_set_catcode_math_subscript:N \_
\NewGlsCompound{^}{_}
% Scratch-\NewGlsCompound im the line above does
% \group_end:
%--------------------
\cs_new:Nn \__MYSTUFF_GLSCOMPOUND_set_scriptdirective_to_tokenlist:NNN
{
% #1 = \l_MYSTUFF_GLSCOMPOUND_superscript_tl /
% \l_MYSTUFF_GLSCOMPOUND_subscript_tl
% #2 = \l_MYSTUFF_GLSCOMPOUND_supparameter_tl /
% \l_MYSTUFF_GLSCOMPOUND_subparameter_tl
% #3 = _ (subscript) or ^ (subscript)
\__MYSTUFF_GLSCOMPOUND_set_scriptdirective_to_tokenlist:NVVN#1#1#2#3
}
\cs_new:Nn \__MYSTUFF_GLSCOMPOUND_set_scriptdirective_to_tokenlist:NnnN
{
% #1 = \l_MYSTUFF_GLSCOMPOUND_superscript_tl /
% \l_MYSTUFF_GLSCOMPOUND_subscript_tl
% #2 = content of \l_MYSTUFF_GLSCOMPOUND_superscript_tl /
% content of \l_MYSTUFF_GLSCOMPOUND_subscript_tl
% #3 = content of \l_MYSTUFF_GLSCOMPOUND_supparameter_tl /
% content of \l_MYSTUFF_GLSCOMPOUND_subparameter_tl
% #4 = _ (subscript) or ^ (subscript)
\tl_if_blank:nTF{#2}
{
\tl_set:Nn
#1
{
\tl_if_blank:oF
{
\exp:w
\tl_if_blank:nTF{#3}{\use:n}{\use_ii_i:nn{#3}}{\exp_end:}
}
{
#4
{
\exp:w
\tl_if_blank:nTF{#3}{\use:n}{\use_ii_i:nn{#3}}{\exp_end:}
}
}
}
}
{
\tl_set:Nn
#1
{
\tl_if_blank:oF
{
\exp:w
\tl_if_blank:nTF{#3}{\use:n}{\use_ii_i:nn{,#3}}{\exp_end:#2}
}
{
#4
{
\exp:w
\tl_if_blank:nTF{#3}{\use:n}{\use_ii_i:nn{,#3}}{\exp_end: #2}
}
}
}
}
}
\cs_generate_variant:Nn
\__MYSTUFF_GLSCOMPOUND_set_scriptdirective_to_tokenlist:NnnN
{ NVVN }
\ExplSyntaxOff
\documentclass[margin=5mm]{standalone}
\usepackage{array}
\usepackage[symbols]{glossaries}
\newglossaryentry{body}{
type=symbols,
name={body},
symbol={B},
description={A body.}
}
\newglossaryentry{phase}{
type=symbols,
name={phase},
symbol={\alpha},
description={A material phase.}
}
\newglossaryentry{index}{
type=symbols,
name={index},
symbol={i},
description={A body index.}
}
\NewGlsCompound{\Body}{
body = {\glssymbol{body}},
args = {O{arg1} O{arg2}},
superscript = {\glssymbol{phase}\IfBlankF{#1}{,#1}},
subscript = {\glssymbol{index}\IfBlankF{#2}{,#2}}
}
%\NewGlsCompound{\Stuff}{
%% body = {stuff},
% args = { },
% superscript = {up},
% subscript = {down}
%}
\begin{document}
\begin{minipage}{\textwidth}
% \(\Stuff^{2up}_{2down}\) \par\bigskip
\renewcommand{\arraystretch}{1.5}
\begin{tabular}{l>{\(\rightarrow\)}c>{\(}l<{\)}}
\verb|\Body|&&\Body\\
\verb|\Body[foo]|&&\Body[foo]\\
\verb|\Body[foo][bar]|&&\Body[foo][bar]\\
\verb|\Body^{X}|&&\Body^{X}\\
\verb|\Body[foo]^{X}|&&\Body[foo]^{X}\\
\verb|\Body[foo][bar]^{X}|&&\Body[foo][bar]^{X}\\
\verb|\Body_{Y}|&&\Body_{Y}\\
\verb|\Body[foo]_{Y}|&&\Body[foo]_{Y}\\
\verb|\Body[foo][bar]_{Y}|&&\Body[foo][bar]_{Y}\\
\verb|\Body^{X}_{Y}|&&\Body^{X}_{Y}\\
\verb|\Body[foo]^{X}_{Y}|&&\Body[foo]^{X}_{Y}\\
\verb|\Body[foo][bar]^{X}_{Y}|&&\Body[foo][bar]^{X}_{Y}\\
\multicolumn{3}{l}{Behavior when specifying optional arguments blank:}\\
\verb|\Body[ ]|&&\Body[ ]\\
\verb|\Body[ ][ ]|&&\Body[ ][ ]\\
\verb|\Body[ ]^{X}|&&\Body[ ]^{X}\\
\verb|\Body[ ][ ]^{X}|&&\Body[ ][ ]^{X}\\
\verb|\Body[ ]_{Y}|&&\Body[ ]_{Y}\\
\verb|\Body[ ][ ]_{Y}|&&\Body[ ][ ]_{Y}\\
\verb|\Body[ ]^{X}_{Y}|&&\Body[ ]^{X}_{Y}\\
\verb|\Body[ ][ ]^{X}_{Y}|&&\Body[ ][ ]^{X}_{Y}\\
\multicolumn{3}{l}{Behavior when specifying embellishments blank:}\\
\verb|\Body^{ }|&&\Body^{ }\\
\verb|\Body[foo]^{ }|&&\Body[foo]^{ }\\
\verb|\Body[foo][bar]^{ }|&&\Body[foo][bar]^{ }\\
\verb|\Body_{ }|&&\Body_{ }\\
\verb|\Body[foo]_{ }|&&\Body[foo]_{ }\\
\verb|\Body[foo][bar]_{ }|&&\Body[foo][bar]_{ }\\
\verb|\Body^{ }_{ }|&&\Body^{ }_{ }\\
\verb|\Body[foo]^{ }_{ }|&&\Body[foo]^{ }_{ }\\
\verb|\Body[foo][bar]^{ }_{ }|&&\Body[foo][bar]^{ }_{ }\\
\multicolumn{3}{l}{Behavior when specifying optional args and
embellishments blank:}\\
\verb|\Body[ ]^{ }|&&\Body[ ]^{ }\\
\verb|\Body[ ][ ]^{ }|&&\Body[ ][ ]^{ }\\
\verb|\Body[ ]_{ }|&&\Body[ ]_{ }\\
\verb|\Body[ ][ ]_{ }|&&\Body[ ][ ]_{ }\\
\verb|\Body[ ]^{ }_{ }|&&\Body[ ]^{ }_{ }\\
\verb|\Body[ ][ ]^{ }_{ }|&&\Body[ ][ ]^{ }_{ }
\end{tabular}
\end{minipage}
\end{document}
注意事項:
請不要做諸如“將
\Body^_{down}
在哪裡_
獲取裝飾參數的值”之類的事情^
。^
除了和表示的可選修飾參數之外,_
巨集\Body
還有兩個後續的[...]
- 分隔可選參數。因此,除了明確指定第一個分隔可選參數並提供其預設值之外,無法僅偏離第二個[...]
分隔可選參數的預設值,同時堅持第一個分隔可選參數的預設值。[...]
[...]
目前(2024 年 1 月 13 日,07:18:40 (UTC + 0000))似乎沒有適當的官方介面來計算 xparse-argument-signature 表示的參數。
因此,\MYSTUFF_xparse_arg_signature_count:n
當未來的 LaTeX 版本發生內部變化時,可能會中斷 - 例如,如果添加更多具有非標準解析/計數的 xparse-argument-types,則需要調整解析參數簽章的機制。由於
\MYSTUFF_xparse_arg_signature_count:n
沒有對作為有效 xparse-argument-signature 的參數實施錯誤檢查。args
巨集的第二個參數的鍵值\NewGlsCompound
也是有效的 xparse-argument-signature,也沒有實作錯誤檢查。因此,如果該值未形成有效的 xparse-argument-signature,則\NewGlsCompound
透過其第一個參數中表示的命令進行定義所觸發的嘗試\NewDocumentCommand
可能會產生有關未知參數類型等的錯誤訊息。