expl3을 사용하여 정렬하기 위해 매크로를 \ index로 확장

Aug 20 2020

\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가됩니다.

증상은이 답변되지 않은 질문과 동일하지만 \ index 인수에 expl3 Expanding 매크로를 사용하고 있습니다.

이제 내 솔루션 (패딩, 콜론, 일반 expl3 bodging)에 충분한 복사 및 붙여 넣기 수정 사항이있어 내가 시도한 모든 것이 아무런 차이가 없거나 완전히 깨 졌기 때문에 명백한 것을 놓치고 있다는 느낌을받습니다. 내가 도대체 ​​뭘 잘못하고있는 겁니까?

답변

1 egreg Aug 20 2020 at 16:30

\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, 나는 얻을

1 F.Pantigny Aug 20 2020 at 16:13

다음 코드가 작업을 수행해야합니다.

\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}