3

I would like to have calculated numbers automatically formatted, so that my pupils can easily read long numbers in my presentations. I figured out that setupunits combined with units, are quite convenient, but they work only if the digits are already formatted with points, and you can't pass a call to tex.print within this macro, as seen in this MWE

\setcharacterspacing[frenchpunctuation]
\mainlanguage[fr]
\language[fr]

\setupunits [method=3,order=reverse]

\starttext
\unit{1.000.333}

\unit{1000333}

{\directlua{tex.print(333*999)}}

\unit{\directlua{tex.print(333*999)}}

\stoptext

formatting output

What I would like is having a fourth line looking like 332 667 (eventually 332.667, which is also correct in French typography).

After a quick search on the web, I found this lua function that could be assigned as a variable and then passed to units

function comma_value(n) -- credit http://richard.warburton.it
    local left,num,right = string.match(n,'^([^%d]*%d)(%d*)(.-)$')
    return left..(num:reverse():gsub('(%d%d%d)','%1,'):reverse())..right
end

The trouble is my lua skills are none. As far as I understand, such a function should be declared in a \startluacode \stopluacode environment, but even then I still have the issue that

\unit{\directlua(comma_value(tex.print(333*999))}

does not have any output.

So,

  • Is there a way to get this unit, comma_value and tex.print working together?
  • How could I tweak the comma_value function to have an French output, something like 332.667 instead of 333,667 (I understand (num:reverse():gsub('(%d%d%d)','%1.') should do the job for integers, but what if decimals are involved?)
  • Last but not least, I suppose there is already a lua function doing the job in ConTeXt internal. Do you know it?
3
  • 1
    You need to call comma_value inside tex.print: \directlua{tex.print(comma_value(333*999))}
    – DG'
    Aug 31, 2019 at 12:26
  • @DG' it is a very good first step: \directlua{tex.print(comma_value(333*999))} output is indeed 332,667 but \unit{\directlua{tex.print(comma_value(333*999))}}has still no output. How can I turn it to be properly processed by unit or, without \unit, to have an output like 332.667 even for digits?
    – sztruks
    Aug 31, 2019 at 14:27
  • 1
    I don't now why, but \unit doesn't take the output. But you can call unit from lua with context.unit. I'll add an example in a minute.
    – DG'
    Aug 31, 2019 at 14:32

2 Answers 2

4

You can call \unit from within lua with context.unit and do all the formatting there:

\setcharacterspacing[frenchpunctuation]
\mainlanguage[fr]
\language[fr]


\startluacode
userdata = userdata or { }

function userdata.comma_value(n) -- credit http://richard.warburton.it
  local left,num,right = string.match(n,'^([^%d]*%d)(%d*)(.-)$')
  return left..(num:reverse():gsub('(%d%d%d)','%1,'):reverse())..right
end

function userdata.formatted_number(n)
  context.unit(userdata.comma_value(n))
end
\stopluacode

\setupunits [method=3]

\starttext

A formatted number: \directlua{userdata.formatted_number(333.3*999.9)}

\stoptext

enter image description here

You can also make a ConTeXt-command that wraps around your lua-code:

\def\formattednumber#1%
  {\directlua{userdata.formatted_number(#1)}}

Now you can just use it like this: \formattednumber{333.3*999.9}

2
  • This is really great. Could you explain the meaning of userdata = userdata or { } and why tex.print is not needed?
    – sztruks
    Aug 31, 2019 at 14:54
  • 2
    userdata is the namespace for your own functions, using it is a precaution against accidentally messing with the lua internals. tex.print is not needed since context.unit already produces the output.
    – DG'
    Aug 31, 2019 at 15:00
2

If you want to do it using \unit, you have to expand the call to \directlua first. I'm using \cldcontext which is essentially a shortcut for \directlua{tex.sprint(...)} (with extra bells and whistles). To expand \cldcontext before \unit I use \expanded.

\setcharacterspacing[frenchpunctuation]
\mainlanguage[fr]
\language[fr]

\setupunits [method=3]

\startluacode
function userdata.comma_value(n) -- credit http://richard.warburton.it
    local left,num,right = string.match(n,'^([^%d]*%d)(%d*)(.-)$')
    return left..(num:reverse():gsub('(%d%d%d)','%1,'):reverse())..right
end
\stopluacode

\starttext

\expanded{\unit{\cldcontext{userdata.comma_value(333.3*999.9)}}}

\stoptext

enter image description here

You must log in to answer this question.

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