将宏扩展为 \index,以便使用 expl3 进行排序

将宏扩展为 \index,以便使用 expl3 进行排序

我有一个文档,其中的需求用自定义宏以文本形式标记\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:10A: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}

相关内容