我有一个文档,其中的需求用自定义宏以文本形式标记\Req{}
,该宏采用逗号分隔的形式的标识符列表[A-F]:[0-9]{4,5}([0-9]{1,2})?
,输出标识符并调用\index
每个标识符。我需要按标识符的数字部分排序输出索引,因此我尝试将标识符的数字部分填充到要传递给的排序键中\index{thing!sort-key@text}
。这是通过以下方式执行的\padreq:n
:
\documentclass{article}
\usepackage{expl3}
\usepackage{imakeidx}
\usepackage{xparse}
\makeindex[name=a2b, columns=1]
\ExplSyntaxOn
% #1 length
% #2 padee
\cs_new:Nn \padint:nn
{ % From : https://tex.stackexchange.com/a/412238/104401
\prg_replicate:nn { #1 - \tl_count:f { \int_to_arabic:n { #2 } } } { 0 }
\int_to_arabic:n { #2 }
}
\cs_generate_variant:Nn \tl_count:n { f }
% takes x.y, pads to 00000x.0y
\cs_new:Nn \padreq:n
{
% temp variables
\seq_clear_new:N \l_padreq_tmp_seq
\tl_clear_new:N \l_padreq_tmp_tl
% split arg 1
\seq_set_split:Nnn \l_padreq_tmp_seq {.} {#1}
\seq_log:N \l_padreq_tmp_seq
% Take the first item...
\seq_pop_left:NNT \l_padreq_tmp_seq \l_padreq_tmp_tl
{ % ... and pad it
%\padint:nn{5}{\l_padreq_tmp_tl}
\padint:nn{5}{\l_padreq_tmp_tl}
}
% Add the middle '.'
.
% Take next split item, which is optional
\seq_pop_left:NNTF \l_padreq_tmp_seq {\l_padreq_tmp_tl}
{ % and pad it
\padint:nn{2}{\l_padreq_tmp_tl}
}
{ % or set a default of 00 if missing
00
}
}
\cs_generate_variant:Nn \padreq:n { x }
\DeclareDocumentCommand{\Req}{m}
{
% Split the csv input
\seq_set_from_clist:Nn \l_tmpa_seq {#1}
% output back to the document, with formatting
[ \seq_use:Nn \l_tmpa_seq {,~} ]
% Index each value, creating a sort key for \index
\seq_map_inline:Nn \l_tmpa_seq {
% Split by colon
% colons with expl3 https://tex.stackexchange.com/a/501346/104401
\use:x {\exp_not:N\seq_set_split:Nnn \exp_not:N\l_tmpb_seq {\c_colon_str} {##1}}
% Pad the 2nd item in the split sequence
\tl_set:Nn \l_tmpa_tl {\padreq:x{\seq_item:Nn \l_tmpb_seq 2}}
\newline ##1~--~\l_tmpa_tl % debug, typesets correctly
\index[a2b]{MWE!\l_tmpa_tl@##1}
}
}
\ExplSyntaxOff
\begin{document}
Hello. \Req{C:230, A:10}
\par
World. \Req{B:101.1}
\printindex[a2b]
\end{document}
这将生成 a2b.idx:
\indexentry{MWE!\padreq:x {230}@C:230}{1}
\indexentry{MWE!\padreq:x {10}@A:10}{1}
\indexentry{MWE!\padreq:x {101.1}@B:101.1}{1}
然而,我认为 makeindex 会按字面意思处理它,并且需要对 idx 文件进行评估。
印刷索引应按 ABC 的顺序排列,但最终却是 BA C。
症状与这个未回答的问题相同,但我正在使用 expl3 \index 参数中的扩展宏。
现在我的解决方案中已经有足够多的复制粘贴修复(填充、冒号、一般解释填充),我感觉我忽略了一些明显的东西,因为我尝试过的所有方法要么没有效果,要么完全破坏了它。我做错了什么?
答案1
该\padreq:n
函数不可扩展。您可以将其输出保存在标记列表中,并使用它来生成索引条目。但是,不应该有.
。
\documentclass{article}
\usepackage{expl3}
\usepackage{imakeidx}
\usepackage{xparse}
\makeindex[name=a2b, columns=1]
\ExplSyntaxOn
% variables and variants
\seq_new:N \l_padreq_tmp_seq
\tl_new:N \l_padreq_paddedargs_tl
\cs_generate_variant:Nn \tl_count:n { f }
\cs_generate_variant:Nn \seq_set_split:Nnn { NV }
% #1 length
% #2 padee
\cs_new:Nn \padint:nn
{ % From : https://tex.stackexchange.com/a/412238/104401
\prg_replicate:nn { #1 - \tl_count:f { \int_to_arabic:n { #2 } } } { 0 }
\int_to_arabic:n { #2 }
}
\cs_generate_variant:Nn \padint:nn { ne }
% takes x.y, pads to 00000x.0y
\cs_new_protected:Nn \padreq:n
{
% split arg 1
\seq_set_split:Nnn \l_padreq_tmp_seq {.} {#1}
%\seq_log:N \l_padreq_tmp_seq
% pad the arguments
\tl_set:Nx \l_padreq_paddedargs_tl
{
% pad the first argument
\padint:ne { 5 } { \seq_item:Nn \l_padreq_tmp_seq { 1 } }
% Take next split item, which is optional
\int_compare:nTF { \seq_count:N \l_padreq_tmp_seq = 1 }
{% no second argument, add a default
00000
}
{
\padint:ne { 5 } { \seq_item:Nn \l_padreq_tmp_seq { 2 } }
}
}
}
\cs_generate_variant:Nn \padreq:n { e }
\DeclareDocumentCommand{\Req}{m}
{
% Split the csv input
\seq_set_from_clist:Nn \l_tmpa_seq {#1}
% output back to the document, with formatting
[ \seq_use:Nn \l_tmpa_seq {,~} ]
% Index each value, creating a sort key for \index
\seq_map_inline:Nn \l_tmpa_seq
{
% Split by colon
\seq_set_split:NVn \l_tmpb_seq \c_colon_str {##1}
% Pad the 2nd item in the split sequence
\padreq:e { \seq_item:Nn \l_tmpb_seq { 2 } }
\index[a2b] {\l_padreq_paddedargs_tl@##1}
}
}
\ExplSyntaxOff
\begin{document}
Hello. \Req{C:230, A:10}
\par
World. \Req{B:101.1}
\printindex[a2b]
\end{document}
这是我在.idx
文件中得到的内容:
\indexentry{0023000000@C:230}{1}
\indexentry{0001000000@A:10}{1}
\indexentry{0010100001@B:101.1}{1}
如果我换成A:10
,A:410
我得到
答案2
以下代码应该可以完成这项工作。
\documentclass{article}
\usepackage{expl3}
\usepackage{imakeidx}
\usepackage{xparse}
\makeindex[name=a2b, columns=1]
\ExplSyntaxOn
% #1 length
% #2 padee
\cs_new:Nn \__aejh_padint:nn
{ % From : https://tex.stackexchange.com/a/412238/104401
\prg_replicate:nn { #1 - \tl_count:f { \int_to_arabic:n { #2 } } } { 0 }
\int_to_arabic:n { #2 }
}
\cs_generate_variant:Nn \tl_count:n { f }
% Will contain the result (that is to say the key constructed on padding)
\tl_clear_new:N \l__aejh_result_tl
\cs_generate_variant:Nn \seq_set_split:Nnn { N V n }
\DeclareDocumentCommand { \Req } { m }
{
\clist_map_inline:Nn { #1 }
{
% Split by colon : we need to use the *value* of \c_colon_str
\seq_set_split:NVn \l_tmpa_seq \c_colon_str { ##1 }
% We retrieve the second item (after the colon)
% Fortunately \seq_item:Nn is fully expandable
\tl_set:Nx \l_tmpa_tl { \seq_item:Nn \l_tmpa_seq 2 }
% We split on an optional dot: \l_tmpb_seq will be of length 1 or 2
\seq_set_split:NnV \l_tmpb_seq { . } \l_tmpa_tl
% We retrive (by poping) the first part
\seq_pop_left:NN \l_tmpb_seq \l_tmpb_tl
% We pad the first part. Fortunately, \__aejh_padint:nn is fully expandable.
\tl_set:Nx \l__aejh_result_tl { \__aejh_padint:nn { 5 } { \l_tmpb_tl } }
% We add the dot
\tl_put_right:Nn \l__aejh_result_tl { . }
% We add the second part, after padding
\seq_pop_left:NNTF \l_tmpb_seq \l_tmpb_tl
{ \tl_put_right:Nx \l__aejh_result_tl { \__aejh_padint:nn 2 { \l_tmpb_tl } } }
{ \tl_put_right:Nn \l__aejh_result_tl { 00 } }
\index [a2b] { MWE ! \l__aejh_result_tl @ ##1 }
}
}
\ExplSyntaxOff
\begin{document}
Hello. \Req{C:230, A:10}
\par
World. \Req{B:101.1}
\printindex[a2b]
\end{document}