# Fill a lua table with lowercase/uppercase pairs.

I would like to add the Letters=Uppercase option to a font which hasn't the needed open type feature built in.

This is (with lualatex) possible like this:

\documentclass{article}
\directlua
{
{
name = "vircase",
type = "multiple",
data =
{
["a"] = {"A"},
["ü"] = {"Ü"},
["ɒ"] = {"A"},       %test non existing chars (nothing happens)
[0x0065] = {0x0045}, %test unicode-numbers (e/E)
["o"] = {"X"},
["o"]=  {"O"},       %test multiple settings (last wins)
["ß"] = {"S","S"},   %special case, should be added manually
},
}
}

\usepackage{fontspec}
\setmainfont{OpenSans-Regular.ttf}%
[
RawFeature=+vircase,
]

\begin{document}
AAAA aaaa ü ß ɒ e o

Hallo Welt!
\end{document}


But I naturally don't want to write all pairs down.

So how could I fill the table with at less fuss as possible? It should be possible to add some pairs manually at the end (for cases like the ß above).

I prefer a solution that uses an existing file in the tex system. I thought about using char-def.lua from context (with require("char-def.lua"). But while it can be loaded without problem in texlive, it doesn't exist in miktex, also I'm not sure if the file will stay stable. Another idea is to use somehow luatex-unicode-letters.tex. But I'm quite open for other ideas.

• Why don't you use the uppercase ẞ (like this one)? May 20, 2017 at 17:52
• do you just want a-z or the full unicode range (ctan hascode to read the unicode data files with the full upper/lower case mappings) used for the expl3 case change functions and other places. May 20, 2017 at 17:53
• [a-z] to [A-Z] could be built with Lua during runtime... May 20, 2017 at 17:54
• @DavidCarlisle: I want more than just a-z (as a german at least äüö is a must too, and we actually also use à and é sometimes ...). Currently full unicode is okay, later it could be usefull to be able to select some ranges (like e.g. the latin block). May 20, 2017 at 18:00
• @Skillmon: The fonts doesn't have an uppercase ß (U+1E9E), beside this I don't like it anyway. Only ascii chars are not enough. I want a (for german and french) usable font. May 20, 2017 at 18:01

Both Miktex and TL includes file UnicodeData.txt, which contains all necessary information. It contains lines in the following form:

0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041


There are several fields delimited with semicolon. Important fields are first, which is current character codepoint, fourth, which is class of character and fifteenth, which contains codepoint of corresponding uppercase character.

We can write simple Lua library which will parse the file and return table with necessary information:

local unicode_data = kpse.find_file("UnicodeData.txt")

local characters = {}
for line in io.lines(unicode_data) do
local fields = line:explode ";"
-- we want to process only uppercase letters
if fields[3] == "Ll" then
local lowercase = tonumber(fields[1],16)
-- uppercae codepoint is in field 15
-- some uppercase letters doesn't have lowercase versions
local uppercase = tonumber(fields[15],16)
characters[lowercase] = uppercase
end
end

return characters


We test for Ll class, which is lowercase letters and construct table with uppercase codepoints. Note that some lowercase chars doesn't have coresponding upeercases, but that's OK, they will not be included in the table.

It can be used in the following way:

\documentclass{article}
\directlua
{
local lowercases = require "makelowercases"
lowercases["ß"] = {"S","S"}
{
name = "vircase",
type = "multiple",
data = lowercases
}
}

\usepackage{fontspec}
\setmainfont{OpenSans-Regular.ttf}%
[
RawFeature=+vircase,
]

\begin{document}
AAAA aaaa ü ß ɒ e o

Hallo Welt!
\end{document}


It will produce the following result:

• I like the solution because the source data is accessible. I wonder if it is worth the trouble to add some range-options. The processing of the unicode-data seems to be quite fast, but I have no idea how it impacts the font use if a large number of substituations are added. May 20, 2017 at 21:25
• @UlrikeFischer I've passed a table with all characters from UnicodeData as data, and the compilation time was only about 0.1 second slower on 70 page document. So I guess that size of the table doesn't have great impact on the performance. May 20, 2017 at 22:46

I would use the included unicode Lua module and fill the uppercase table by a loop, like this:

\documentclass{article}
\directlua
{
local upper = unicode.utf8.upper
local char = unicode.utf8.char

local data = {}
for c = 0x20, 0x0500 do
data[char(c)] = {upper(char(c))}
end

data["ß"] = {"S","S"}

name = "vircase",
{
type = "multiple",
data = data,
}
}
}

\usepackage{fontspec}
\setmainfont{CMU Serif}%
[
RawFeature=+vircase,
]

\begin{document}
AAAA aaaa ü ß ɒ e o

Hallo Welt!

Привет, Мир!
\end{document}


Since I use TexLive 2016, the syntax of fonts.handlers.otf.addfeature arg is a bit different, you can adjust it. I've limited the loop up to 0x0500 which covers Latin scripts, Greek and Cyrillic. Some Cyrillic example is also added (and works!).

• I would never have thought about the inbuild library. Do you know how good the upper() library is? May 20, 2017 at 20:28
• Can't tell for sure. It comes from essentially undocumented slnunicode library. As far as I can see, the Unicode data in there has been taken from the (fairly old as for now) Tcl distribution, which seems to be good enough for me. May 20, 2017 at 20:52