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?
  • 1
    You need to call comma_value inside tex.print: \directlua{tex.print(comma_value(333*999))} – DG' Aug 31 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 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 at 14:32
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}

  • This is really great. Could you explain the meaning of userdata = userdata or { } and why tex.print is not needed? – sztruks Aug 31 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 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.