3

I'm trying to write some Latex expl3 functions. I'm new to this so maybe the problem is obvious but well...

I want to code macros where I can call a command with one argument and count how many time a given argument has been passed. Then I output the totals in a sorted list. Everything works ok but in my list, the french accents vanish. Here is a minimal code:

\documentclass[oneside,12pt,a4paper]{article}

\usepackage[utf8]{inputenc} 

\usepackage{expl3}

\ExplSyntaxOn
%% creates a new token list
\prop_new:N \g_jbmlist_prop
\int_new:N \l_curval_int

\newcommand\addmaterial[1]{%
\group_begin:
    % create key in g_jbmlist_prop if new and sets to 0.
    \prop_gput_if_new:Nnn \g_jbmlist_prop {#1} 0

    % defines int variable l_curval_int as the value of the prop.
    \int_set:Nn \l_curval_int { \prop_item:Nn \g_jbmlist_prop {#1} }
    \int_incr:N \l_curval_int  % increments the value
    \prop_gput:NnV \g_jbmlist_prop {#1} {\l_curval_int} % put it back.
  \group_end:
}

\NewDocumentCommand{\outputmatlistitems}{}{
  % \prop_show:N \g_jbmlist_prop
  \group_begin:
    % \int_new:N \l_curval_int
    % declare a new list
    \seq_new:N \l_tmpjba_seq 
    % new function to push into list
    \cs_set:Npn \push_to_seq:nn ##1##2 {
      \seq_put_right:Nn \l_tmpjba_seq {##1}
    }
    % push g_jbmlist_prop into it.
    \prop_map_function:NN \g_jbmlist_prop \push_to_seq:nn
    
    % sort the sequence
    \seq_sort:Nn \l_tmpjba_seq
    {
      \str_compare:nNnTF { ##1 } > { ##2 }
      { \sort_return_swapped: }
      { \sort_return_same: }
    }

    % define the way items will be displayed.    
    \cs_set:Npn \output_item:n ##1 {
      % prints
      \item {\expandafter ##1}: \prop_item:Nn \g_jbmlist_prop {##1}
      }
    % output the sorted sequence
    \begin{itemize}
      \seq_map_function:NN \l_tmpjba_seq \output_item:n
    \end{itemize}
  \group_end:
}
\ExplSyntaxOff


% \geometry{a4paper,inner=2.1cm,outer=2.1cm,top=2cm,bottom=2cm}

\begin{document}

En Français "maître" était accentué.

\addmaterial{scotch}
\addmaterial{règle}
\addmaterial{règle}

\outputmatlistitems

\end{document}

And I get:

missing accent in the list rendering

Where the list should give:

  • règle:2
  • scotch:1

My environnement is Mac with pdfTeX 3.141592653-2.6-1.40.24 (TeX Live 2022) in case it matters.

2
  • Your example works fine with LuaLaTeX. Since you seem to want to use UTF8, you should probably use a compiler suited for this encoding, if you don't have external constraints.
    – Miyase
    Jun 21, 2023 at 19:44
  • The issue is that you try to typeset the keys of a prop. Those aren't meant for typesetting, they get stringified. In UTF8-engines this might not always be an issue, but in pdfLaTeX you'll get garbish if this includes non-ASCII characters.
    – Skillmon
    Jun 21, 2023 at 19:58

2 Answers 2

4

The problem is that typesetting the keys of a prop is not reliable. I use two property lists, indexed by the items.

However, I warn you that string sorting doesn't really work.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\addmaterial}{m}
 {
  \bobmorane_material_add:n { #1 }
 }

\NewDocumentCommand{\outputmatlistitems}{}
 {
  \bobmorane_material_output:
 }

\prop_new:N \g_bobmorane_material_items_prop
\prop_new:N \g_bobmorane_material_counts_prop
\seq_new:N \l__bobmorane_material_sort_seq

\cs_new_protected:Nn \bobmorane_material_add:n
 {
  \prop_gput_if_new:Nnn \g_bobmorane_material_items_prop { #1 } { #1 }
  \prop_if_in:NnTF \g_bobmorane_material_counts_prop { #1 }
   {
    \prop_gput:Nnx \g_bobmorane_material_counts_prop { #1 }
     {
      \int_eval:n { \prop_item:Nn \g_bobmorane_material_counts_prop { #1 } + 1 }
     }
   }
   {
    \prop_gput:Nnn \g_bobmorane_material_counts_prop { #1 } { 1 }
   }
 }

\cs_new_protected:Nn \bobmorane_material_output:
 {
  \seq_clear:N \l__bobmorane_material_sort_seq
  \prop_map_inline:Nn \g_bobmorane_material_counts_prop
   {
    \seq_put_right:Nn \l__bobmorane_material_sort_seq { ##1 }
   }
  \seq_sort:Nn \l__bobmorane_material_sort_seq
   {
    \str_compare:nNnTF { ##1 } > { ##2 }
     { \sort_return_swapped: }
     { \sort_return_same: }
   }
  \begin{itemize}
  \seq_map_function:NN \l__bobmorane_material_sort_seq \__bobmorane_material_output:n
  \end{itemize}
 }

\cs_new_protected:Nn \__bobmorane_material_output:n
 {
  \item
  \prop_item:Nn \g_bobmorane_material_items_prop { #1 }
  :
  \prop_item:Nn \g_bobmorane_material_counts_prop { #1 }
 }

\ExplSyntaxOff

\begin{document}

\addmaterial{aabbb}
\addmaterial{riri}
\addmaterial{scotch}
\addmaterial{règle}
\addmaterial{riri}
\addmaterial{règle}

\outputmatlistitems

\end{document}

enter image description here

3
  • Why do you use the O(n) function \prop_item:Nn instead of the O(1) function \prop_get:NnN in an unexpandable context?
    – Skillmon
    Jun 22, 2023 at 5:58
  • @Skillmon Laziness? ;-)
    – egreg
    Jun 22, 2023 at 8:25
  • Good reason :D (this is just here to reach the min. message length)
    – Skillmon
    Jun 22, 2023 at 8:32
6

The following solves the stringification of l3prop by storing the non-stringified version in the prop as well.

The price we have to pay is that the mapping over the data gets more complicated (\use_i:nn and \use_ii:nn to get the printable version and number, and \exp_after:wN to expand the \l_tmpa_tl variable here and there).

I've also replaced your \prop_item:Nn usages with the much faster \prop_get:NnN (you should only use \prop_item:Nn if you have to work by expansion), the same is true for your \..._map_function:NN usages, that I've replaced with \..._map_inline:Nn versions.

\documentclass[oneside,12pt,a4paper]{article}

% \usepackage[utf8]{inputenc} % no longer needed with recent LaTeX versions

\usepackage{expl3}

\ExplSyntaxOn
%% creates a new token list
\prop_new:N \g_jbmlist_prop
\int_new:N \l_curval_int
% declare a new list
\seq_new:N \l_tmpjba_seq 

\newcommand\addmaterial[1]{%
  \group_begin:
    % create key in g_jbmlist_prop if new and sets to 0.
    \prop_gput_if_new:Nnn \g_jbmlist_prop {#1} { {#1} {0} }

    % defines int variable l_curval_int as the value of the prop.
    \prop_get:NnN \g_jbmlist_prop {#1} \l_tmpa_tl
    \prop_gput:Nne \g_jbmlist_prop {#1}
      {
        { \exp_not:n {#1} }
        \int_eval:n { \exp_after:wN \use_ii:nn \l_tmpa_tl + \c_one_int }
      }
  \group_end:
}

\NewDocumentCommand{\outputmatlistitems}{}{
  % \prop_show:N \g_jbmlist_prop
  \group_begin:
    % push g_jbmlist_prop into it.
    \prop_map_inline:Nn \g_jbmlist_prop
      { \seq_put_right:Nx \l_tmpjba_seq { \exp_not:o { \use_i:nn ##2 } } }
    
    % sort the sequence
    \seq_sort:Nn \l_tmpjba_seq
      {
        \str_compare:nNnTF { ##1 } > { ##2 }
          { \sort_return_swapped: }
          { \sort_return_same: }
      }

    % define the way items will be displayed.    
    % output the sorted sequence
    \begin{itemize}
      \seq_map_inline:Nn \l_tmpjba_seq
        {
          \item ##1:
          \prop_get:NnN \g_jbmlist_prop {##1} \l_tmpa_tl
          \exp_after:wN \use_ii:nn \l_tmpa_tl
        }
    \end{itemize}
  \group_end:
}
\ExplSyntaxOff


% \geometry{a4paper,inner=2.1cm,outer=2.1cm,top=2cm,bottom=2cm}

\begin{document}

En Français "maître" était accentué.

\addmaterial{scotch}
\addmaterial{règle}
\addmaterial{règle}

\outputmatlistitems

\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .