I would like to code an advanced macro that would look like

\begin{exercise}[....]
bla bla bla
\end{exercise}


In the brackets [....], I would put strings like :

• FFFHHC
• F
• HHF
• CCH
• ?
• etc.

The idea is to count to the number of F, H and C and take different actions depending on the result. In my mind, FFF will print three "lightning" symbols next to the exercise, H will print one star, HH two stars, CC two computer symbols, ? will print one question mark, etc.

(F stand for "flash", H for "hard", C for "computer", ? for "unknown", etc.)

What direction should I take? Do you have any hint (like somewhere where I could copy some code)? Any package that would help me?

I would prefer a LaTeX only solution but I'm also interested to know if LuaLaTeX can make this kind of things much easier.

• There are some easy answers on the site using latex3 syntax to first split it into a list and then run a case construction on each char to determine what to do for each. So this is easily doable in latex, no need for lua – daleif Apr 15 '18 at 11:11
• Do you have some links that I could use to learn how to do that? – Colas Apr 15 '18 at 11:33
• your description is a bit contradictory, do you need to pre-parse the argument and count the number of H or do you just want t make H print a star C a computer symbol etc and so HH just prints two star naturally without counting? you can do either but obviously just printing teh string is easier – David Carlisle Apr 15 '18 at 11:54
• Thanks for your comment. I would like to parse the string before. – Colas Apr 15 '18 at 12:01
• @Colas I may add that version but I'll post a simpler case (as I have just done it:-) – David Carlisle Apr 15 '18 at 12:06

\documentclass{article}

\newenvironment{zzz}[1][]{%
\quote\strut\marginpar{\zzzz#1!}\ignorespaces}
{\endquote}

\def\zzzz#1{\csname zzz#1\endcsname\zzzz}

\def\zzzH{$\ast$}
\def\zzzF{$|$}
\def\zzzC{$\,\rule{4pt}{5pt}\,$}
\expandafter\def\csname zzz?\endcsname{?}
\expandafter\def\csname zzz!\endcsname#1{}

\begin{document}

\begin{zzz}
one two three
\end{zzz}

\begin{zzz}[CCCH]
one two three
\end{zzz}

\begin{zzz}[FF]
one two three
\end{zzz}

\begin{zzz}[CF?]
one two three
\end{zzz}

\end{document}


This directly prints the symbols but you could of course make the macros increment some counter instead and defer all printing until after the whole collection is known.

\documentclass{article}

\newenvironment{zzz}[1][]{%
\quote\strut\marginpar{%
\Hc=0
\Fc=0
\Cc=0
\Qc=0
\zzzz#1!%
There are \the\Cc\ C and \the\Fc\ F}\ignorespaces}
{\endquote}

\def\zzzz#1{\csname zzz#1\endcsname\zzzz}

\newcount\Hc
\newcount\Fc
\newcount\Cc
\newcount\Qc

\expandafter\def\csname zzz!\endcsname#1{}

\begin{document}

\begin{zzz}
one two three
\end{zzz}

\begin{zzz}[CCCH]
one two three
\end{zzz}

\begin{zzz}[FF]
one two three
\end{zzz}

\begin{zzz}[CF?]
one two three
\end{zzz}

\end{document}


This is an expl3 implementation: with \regex_count:nnN we can set an integer variable to the number of occurrences of a letter and populate a token list variable with the number of required repetitions.

In this implementation, I set the symbols at the left of “Exercise“, in the margin.

\documentclass{article}
\usepackage{xparse,marvosym,amsthm}

\ExplSyntaxOn

\theoremstyle{definition}
\newtheorem{innerexercise}
{
\makebox[0pt][r]{\l__colas_symbols_tl\enspace}Exercise
}

\tl_new:N \l__colas_symbols_tl
\prop_new:N \g_colas_symbols_prop
\clist_new:N \g_colas_symbols_clist
\prop_gset_from_keyval:Nn \g_colas_symbols_prop % the equivalents
{
F=\Lightning,
H=\textasteriskcentered,
C=\Keyboard,
?=?,
}
\clist_gset:Nn \g_colas_symbols_clist { F, H, C, ? } % the final order

\NewDocumentEnvironment{exercise}{o}
{
\IfValueT{#1} { \colas_symbols_add:n { #1 } }
\begin{innerexercise}
}
{
\end{innerexercise}
}

{
\tl_clear:N \l__colas_symbols_tl
\clist_map_inline:Nn \g_colas_symbols_clist
{
\regex_count:nnN { ##1 } { #1 } \l_tmpa_int
\tl_put_right:Nx \l__colas_symbols_tl
{
\prg_replicate:nn { \l_tmpa_int } { \prop_item:Nn \g_colas_symbols_prop { ##1 } }
}
}
}

\ExplSyntaxOff

\begin{document}

\begin{exercise}
Simple one
\end{exercise}

\begin{exercise}[FFFHHC]
Harder one
\end{exercise}

\begin{exercise}[F]
Harder one
\end{exercise}

\begin{exercise}[HHF]
Harder one
\end{exercise}

\begin{exercise}[CHC]
Harder one
\end{exercise}

\begin{exercise}[?]
Harder one
\end{exercise}

\end{document}


• I tried and copy/paste your code but it does not work. Here is the error: ./bac_a_sable.tex:16: Undefined control sequence. l.16 \prop_gset_from_keyval:Nn \g_colas_symbols_prop % the equivalents – Colas Apr 15 '18 at 15:26
• @Colas You need to update l3kernel (and l3packages). – Bruno Le Floch Apr 15 '18 at 15:27
• Which line of code should I add? – Colas Apr 15 '18 at 15:36
• @Colas No line of code; update your TeX distribution – egreg Apr 15 '18 at 15:58

Here is a solution with LuaTeX.

\documentclass{article}
\usepackage{amsthm,marvosym,luacode}

\begin{luacode*}
function convert(str)
local symbols = {
F = "\\Lightning",
H = "\\textasteriskcentered",
C = "\\Keyboard",
["?"] = "?",
}
local order = { "F", "H", "C", "?" }
local count = {}
for c in str:gmatch"." do
count[c] = (count[c] or 0) + 1
end
for _,s in ipairs(order) do
tex.sprint(string.rep(symbols[s],count[s] or 0))
end
end
\end{luacode*}

\newtheoremstyle{exercise}%
{}% space above
{}% space below
{}% body font
{}% indent
{\makebox[0pt][r]{\directlua{convert([[#3]])}\enspace}%

\theoremstyle{exercise}
\newtheorem{exercise}{Exercise}

\begin{document}

\begin{exercise}
Simple one
\end{exercise}

\begin{exercise}[FFFHHC]
Harder one
\end{exercise}

\begin{exercise}[F]
Harder one
\end{exercise}

\begin{exercise}[HHF]
Harder one
\end{exercise}

\begin{exercise}[CHC]
Harder one
\end{exercise}

\begin{exercise}[?]
Harder one
\end{exercise}

\end{document}