The width of the widest character, relatively to the font settings

I write a software that generates LaTeX code. For various reasons, I'd like to know the width of the largest character, relatively to the current font settings.

As a developer, I wrote a Perl script that produces a LaTeX document (let us call it "output.tex"). This LaTeX document ("output.tex"), once processed through LuaLaTeX produces a files that contain the width (and other dimensions) of all characters (let use call it "output.dim").

Please note that if you are interested in the Perl script, you can find it here (this is the file "char.pl").

The file "output.tex" looks like :

Please note that I don't show here all the content of the file. I removed some lines. You can get the full file on this permanent link.

\documentclass{article}

\usepackage[a4paper]{geometry}
\renewcommand{\normalsize}{\fontsize{10pt}{12pt}\selectfont}

\usepackage{newfile}
\newoutputstream{dimensions}
\openoutputfile{\jobname.dim}{dimensions}

\setlength{\parindent}{0pt}
\setlength{\fboxsep}{0px}

\begin{document}
\newsavebox{\boxaaaa}
\savebox{\boxaaaa}{\framebox{a}}

\newsavebox{\boxbaaa}
\savebox{\boxbaaa}{\framebox{b}}

\newsavebox{\boxcaaa}
\savebox{\boxcaaa}{\framebox{c}}

% More lines...

\newsavebox{\boxzzka}
\savebox{\boxzzka}{\framebox{8}}

\newsavebox{\boxzzla}
\savebox{\boxzzla}{\framebox{9}}

\end{document}


The file "output.dim" looks like :

Please note that I don't show here all the content of the file. I removed some lines. You can get the full file on this permanent link.

a: 5.8pt, 4.70554pt, 0.4pt
b: 6.35556pt, 7.34444pt, 0.4pt
c: 5.24443pt, 4.70554pt, 0.4pt
...
8: 5.8pt, 6.84444pt, 0.4pt
9: 5.8pt, 6.84444pt, 0.4pt


OK. So, using the content of the generated file "output.dim", I can get the dimensions of all characters for the given font settings. And, thus, I can get the maximum width of a character (a simple script would do the job).

This solution works... however, it is not elegant. You have to execute (Perl) scripts to get dimensions, and then you can produce a LaTeX document (through other scripts). Besides, all the calculations on dimensions should be handled by LaTeX.

Do you have a more elegant solution to get the width of the widest character, relatively to the current font settings ?

Thanks.

• It depends on what you mean by “character”: does the em-dash count, for instance? – egreg Jul 16 '18 at 9:50
• You don't need to box all your chars, you can use eg. \the\fontcharwd\font\w to get the width of the w. But beside this it really depends on what you mean by "char". – Ulrike Fischer Jul 16 '18 at 9:53
• Thank you for your responses. I call a "character" any "symbol" that can be used in a text (this includes accented characters, or mathematical symbols, although I did not mention it in my example). – Denis Beurive Jul 16 '18 at 11:19
• as you are using lualatex you can use fonts with a lot (hundreds of thousands) of characters, do you really generate a list of all of them in perl? – David Carlisle Jul 16 '18 at 11:54

This is scalable: if not only alphanumerics are needed, just add to the initial list (accented characters should be braced for safety, so {é}, for instance).

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{xparse}

\ExplSyntaxOn
\tl_const:Nn \c_beurive_alphabet_tl
{
0123456789
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
}

\box_new:N \l__beurive_widest_box
\dim_new:N \l__beurive_widest_dim
\tl_new:N \l__beurive_widest_tl
\tl_new:N \widestchar
\dim_new:N \widestcharwd

\NewDocumentCommand{\computewidest}{O{}}
{
\group_begin:
#1 % optionally select a font
\dim_zero:N \l__beurive_widest_dim
\tl_clear:N \l__beurive_widest_tl
\tl_map_inline:Nn \c_beurive_alphabet_tl
{
\hbox_set:Nn \l__beurive_widest_box { ##1 }
\dim_compare:nT { \box_wd:N \l__beurive_widest_box > \l__beurive_widest_dim }
{
\dim_set:Nn \l__beurive_widest_dim { \box_wd:N \l__beurive_widest_box }
\tl_set:Nn \l__beurive_widest_tl { ##1 }
}
}
\dim_gset_eq:NN \widestcharwd \l__beurive_widest_dim
\tl_gset_eq:NN \widestchar \l__beurive_widest_tl
\group_end:
}
\ExplSyntaxOff

\begin{document}

\computewidest
The widest character is \widestchar'', width \the\widestcharwd

\bigskip

\computewidest[\Large\bfseries\itshape]
The widest character is \widestchar'', width \the\widestcharwd

\bigskip

\computewidest[\ttfamily]
The widest character is \widestchar'', width \the\widestcharwd

\end{document}


• Thank you for this example. I don't understand the code yet, but I will analyse it. I did not know that LaTeX can be used to write such algorithm. – Denis Beurive Jul 16 '18 at 11:15
• @grep: I understand that you define variables and functions, and you use imperative programming control structure (branching, loops...). I also "guess" that you assign types to variables. Thus, I'd say that LaTeX is more than a markup language (like HTML). It is a markup language and a programming language that uses the imperative paradigm. OK, but where can I find documentation about the "programming language" feature ? All I find is documentation about the use of LaTeX as a markup language. I found the TexBook. However, the TexBook does not mention some macro that you use – Denis Beurive Jul 16 '18 at 14:07
• @DenisBeurive It's called expl3 and is the base programming language for the future LaTeX3. Do texdoc expl3 and texdoc interface3` for a start. – egreg Jul 16 '18 at 14:09
• That's interesting. I tested your code with my installation of TexLive (v 6.2.1) which includes LuaLaTeX version beta-0.80.0. And it works. I thought that LaTeX V3 was not released yet (I heard about it on latex-project.org/latex3). Thus, LaTeX 3 is already implemented (at least part of it). And we can already use it. Is it correct ? – Denis Beurive Jul 16 '18 at 14:47
• @DenisBeurive The programming layer is quite stable now. – egreg Jul 16 '18 at 14:49