TeX - LaTeX Asked on July 11, 2021
I have a document with requirements marked up in text with a custom macro Req{}
, which takes a comma separated list of identifiers of the form [A-F]:[0-9]{4,5}([0-9]{1,2})?
, outputs the identifiers and calls index
for each of them. I need the index to be output ordered by the numeric part of the identifier, so am attempting to pad the numeric part of the identifier into a sort key to pass to index{thing!sort-key@text}
. This is performed by 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:Nseq_set_split:Nnn exp_not:Nl_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}
This produces an a2b.idx of:
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}
whereas, I think, makeindex will treat it literally and it needs to be evaluated for the idx file.
Printed index should be in order A B C, but ends up B A C.
The symptoms are the same as this unanswered question, but I’m using expl3
Expanding macro in index argument.
There are now enough copy ‘n paste fixes in my solution (padding, colons, general expl3 bodging) that I get the feeling I’m missing something obvious, as everything I’ve tried has either made no difference or broken it completely. What am I doing wrong?
The padreq:n
function is not expandable. You can save its output in a token list and use it for producing the index entry. There should not be the .
, however.
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}
This is what I get in the .idx
file:
indexentry{0023000000@C:230}{1}
indexentry{0001000000@A:10}{1}
indexentry{0010100001@B:101.1}{1}
If I change A:10
into A:410
, I get
Correct answer by egreg on July 11, 2021
The following code should do the job.
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}
Answered by F. Pantigny on July 11, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP