What is mapping good for?
Maps are useful for orientation when crossing boundaries into alternate spaces.
Font mapping is most helpful for those dealing with long texts across script boundaries (although nothing beats a native speaker and typist). If there are only a small number of frequently used characters involved, an alternate method is to define some macros.
More specifically, for fonts, substituting one set of characters for another set, can be a useful shortcut as an input method. Mapping decouples the character from the keyboard key. (Except for spaces: the space character has already been converted to a space token (a skip) by the time font substitution occurs - see egreg's comment: Mapping ‘space + character’ into ‘non-breaking space + character’.) The result is that many more glyphs can be accessed than are available from the individual keys on the keyboard. It's a bit like Latex macros, only at the font level.
In effect, mapping is a kind of lookup table for fonts. I can map the Latin letters th
to Greek θ
, or, in the other direction, map Greek θ
to Latin th
. Latin khei
to Coptic ϧ
; the character sequence cdragon
to 龍
. And so on. (Astute readers will notice the similarity to the auto-correct feature of spell-checkers; anything with string substitution, in fact.)
Tex has some built-in font mapping (-- becomes an en-dash, for example), for typesetting some basic ligatures.
Mapping is intended to allow the transliteration from one script into another, so that texts become accessible to those who can't read the source script (and texts can be composed by those who do not have, or do not have the time to learn, the destination-script keyboard (assuming one exists)).
Line-breaking, text-wrapping and hyphenation are things to watch out for in space-less scripts, but that happens normally anyway without mapping.
Also, be careful that the character(s) you map to actually exist(s) in the destination font. For example, Noto Sans Old Persian
does not have a zero-width non-joiner (yet).
The from
side elements (the left-hand side of the lookup table) ought to be unique. To be useful, a set of characters can't map to two or more other sets, logically speaking. Think of regular expressions. And pattern matching is similar: if you have three glyphs, niis
, ni
and is
(I'm thinking Old Babylonian, here), and you map the second and third ones but forget the first, and then run your mapped font across niis
, it will be parsed into ni
+ is
, not niis
.


MWE
\documentclass[12pt]{article}
\usepackage{fontspec}
\usepackage{xcolor}
\usepackage{ascmac}
\setmainfont{Linux Libertine}
\newfontface\egyfe{Noto Sans Egyptian Hieroglyphs}
\newfontface\plaineh{Noto Sans Egyptian Hieroglyphs}
\newfontface\egym[Mapping=gardnernum-to-hieroglyph]{Code2003}
\newfontface\egyn[Mapping=gardnernum-to-hieroglyph2,Color=blue,Scale=2.5]{Noto Sans Egyptian Hieroglyphs}
\expandafter\newcommand\csname A001\endcsname{\symbol{"13000}}
\DeclareTextFontCommand{\texthg}{\egym}
\DeclareTextFontCommand{\texthi}{\egyn}
\newenvironment{hyphblnk}{%
\let\oldhyphenchar\hyphenchar%
\hyphenchar\font=\string"20}{\let\hyphenchar\oldhyphenchar}
\newenvironment{thiero}
{\egym\huge\ignorespaces}
{\ignorespacesafterend}
\renewcommand{\tabcolsep}{1pt}
\newcommand\operfont{Noto Sans Old Persian}
\newcommand\opercolour{blue}
\newcommand\opermapping{latin-to-oldpersian}
\newfontface\fmoper[Mapping=\opermapping ,Colour=\opercolour]{\operfont}
\newfontface\fmopertranse[Mapping=oldpersian-to-latine,Colour=red]{Noto Serif}
\newenvironment{opertranslite}
{\fmopertranse}%\hyphenrules{nohyphenation}\ignorespaces}
{\ignorespacesafterend}
\begin{document}
\section{Mapping}
If I wanted to typeset an Egyptian hieroglyph (say, Gardiner number A001), I could tap the relevant key on my Egyptian hieroglyphic keyboard \keytop{{\Huge\texthg{A001}}} and it appears in my file (with a suitable font active).
Alternatively, I can refer to it indirectly with \verb|\symbol{"13000}| = {\plaineh\Huge\symbol{"13000}}. To save having to look up all those unicode hex numbers every time, I can define a mnemonic macro named \verb|\A001| with \texttt{\textbackslash expandafter\textbackslash newcommand\textbackslash csname A001\textbackslash endcsname\{\textbackslash symbol\{"13000\}\}} and call it with \texttt{\textbackslash csname A001\textbackslash endcsname} = {\plaineh\Huge\csname A001\endcsname}. Which is a bit much to type if there are more than a few hundred hieroglyphs involved.
So I set up a font mapping, so that whenever I type the four characters \textbf{A001}, they are substituted with U+13000, and {\Huge \texthg{A001}} appears in the output.
The first step is a mapping file, a text file with a \verb|.map| extension, which will be compiled into a binary \verb|.tec| file with \texttt{teckit\_compile}.
To be practical, typing \textbf{A1} is less effort than typing \textbf{A001}, so a mapping file will contain the shorter:
\begin{quotation}
U+0041 U+0031 <> U+13000
\end{quotation}
The second step in using a mapping is calling it into play when defining the font. Say my compiled mapping file is called \texttt{foo.tec}. Then I call it with
\begin{quotation}\noindent
\texttt{\textbackslash newfontface\textbackslash egyn[
Mapping=foo,
Color=blue,
Scale=2.5]\\
\{Noto Sans Egyptian Hieroglyphs\}}
\end{quotation}
to set up a mapped font named \verb|egyn|. Now, whenever I type \textbf{A1} wherever font \texttt{\textbackslash egyn} is active, I get {\texthi{A1}}.
\begin{quotation}\noindent
From A001 { \huge \texthg{A001}} to AA032 { \huge \texthg{AA032}}
\end{quotation}
\newpage
\section{There and Back Again}
Say there is some writing on the valley wall:
%Original:
\begin{quotation}
{
\fmoper\Large
\XeTeXlinebreaklocale "peo"
\noindent
𐏃𐎧𐎠𐎶𐎴𐎡𐏁𐎡𐎹𐏐𐏃𐎡𐎹𐏐𐎡𐎶𐎶𐏐𐎫𐎨𐎼𐎶𐏐𐎠𐎤𐎢𐎴𐎢𐏁𐏐 𐏃𐎧𐎠𐎶𐎴𐎡𐏁𐎡𐎹𐏐𐏃𐎡𐎹𐏐𐎡𐎶𐎶𐏐𐎫𐎨𐎼𐎶𐏐𐎠𐎤𐎢𐎴𐎢𐏁𐏐𐏃𐎧𐎠𐎶𐎴𐎡𐏁𐎡𐎹𐏐𐏃𐎡𐎹𐏐𐎡𐎶𐎶𐏐𐎫𐎨𐎼𐎶𐏐𐎠𐎤𐎢𐎴𐎢𐏁𐏐𐏃𐎧𐎠𐎶𐎴𐎡𐏁𐎡𐎹𐏐𐏃𐎡𐎹𐏐𐎡𐎶𐎶𐏐𐎫𐎨𐎼𐎶𐏐𐎠𐎤𐎢𐎴𐎢𐏁𐏐𐏃𐎧𐎠𐎶𐎴𐎡𐏁𐎡𐎹𐏐𐏃𐎡𐎹𐏐𐎡𐎶𐎶𐏐𐎫𐎨𐎼𐎶𐏐𐎠𐎤𐎢𐎴𐎢𐏁𐏐
}
\end{quotation}
Transliterating
{\fmoper xa-a} (xa+a)
to
\begin{opertranslite}
𐎧𐎠
\end{opertranslite}
and
{\fmoper ha-i} (ha+i)
to
\begin{opertranslite}
𐏃𐎡
\end{opertranslite}
and
{\fmoper ku-u} (ku+u)
to
\begin{opertranslite}
𐎤𐎢
\end{opertranslite}
and so on, gives:
\begin{quotation}
%\elongoper{%
\begin{opertranslite}
\XeTeXlinebreaklocale "peo"
\noindent
𐏃𐎧𐎠𐎶𐎴𐎡𐏁𐎡𐎹𐏐𐏃𐎡𐎹𐏐𐎡𐎶𐎶𐏐𐎫𐎨𐎼𐎶𐏐𐎠𐎤𐎢𐎴𐎢𐏁𐏐 𐏃𐎧𐎠𐎶𐎴𐎡𐏁𐎡𐎹𐏐𐏃𐎡𐎹𐏐𐎡𐎶𐎶𐏐𐎫𐎨𐎼𐎶𐏐𐎠𐎤𐎢𐎴𐎢𐏁𐏐𐏃𐎧𐎠𐎶𐎴𐎡𐏁𐎡𐎹𐏐𐏃𐎡𐎹𐏐𐎡𐎶𐎶𐏐𐎫𐎨𐎼𐎶𐏐𐎠𐎤𐎢𐎴𐎢𐏁𐏐𐏃𐎧𐎠𐎶𐎴𐎡𐏁𐎡𐎹𐏐𐏃𐎡𐎹𐏐𐎡𐎶𐎶𐏐𐎫𐎨𐎼𐎶𐏐𐎠𐎤𐎢𐎴𐎢𐏁𐏐𐏃𐎧𐎠𐎶𐎴𐎡𐏁𐎡𐎹𐏐𐏃𐎡𐎹𐏐𐎡𐎶𐎶𐏐𐎫𐎨𐎼𐎶𐏐𐎠𐎤𐎢𐎴𐎢𐏁𐏐
\end{opertranslite}%
%}
\end{quotation}
\end{document}
There are several mapping files involved.
latin-to-oldpersian:
; TECkit mapping for TeX input conventions <-> Unicode characters
LHSName "latin-to-oldpersian"
RHSName "UNICODE"
pass(Unicode)
; ligatures from Knuth's original CMR fonts
U+002D U+002D <> U+2013 ; -- -> en dash
U+002D U+002D U+002D <> U+2014 ; --- -> em dash
U+0027 <> U+2019 ; ' -> right single quote
U+0027 U+0027 <> U+201D ; '' -> right double quote
U+0022 > U+201D ; " -> right double quote
U+0060 <> U+2018 ; ` -> left single quote
U+0060 U+0060 <> U+201C ; `` -> left double quote
U+0021 U+0060 <> U+00A1 ; !` -> inverted exclam
U+003F U+0060 <> U+00BF ; ?` -> inverted question
; additions supported in T1 encoding
U+002C U+002C <> U+201E ; ,, -> DOUBLE LOW-9 QUOTATION MARK
U+003C U+003C <> U+00AB ; << -> LEFT POINTING GUILLEMET
U+003E U+003E <> U+00BB ; >> -> RIGHT POINTING GUILLEMET
;U+0020 > U+0020 ; space maps to space
U+002D > U+200D ; hyphen as Zero Width Joiner
U+002E > U+200D ; dot as Zero Width Joiner
U+007C > U+200C ; pipe as Zero Width Non-Joiner
U+0061 <> U+103A0 ; a 𐎠
U+0069 <> U+103A1 ; i 𐎡
U+0075 <> U+103A2 ; u 𐎢
U+006B U+0061 <> U+103A3 ; ka 𐎣
U+006B U+0075 <> U+103A4 ; ku 𐎤
U+0067 U+0061 <> U+103A5 ; ga 𐎥
U+0067 U+0075 <> U+103A6 ; gu 𐎦
U+0078 U+0061 <> U+103A7 ; xa 𐎧
U+0063 U+0068 U+0061 <> U+103A8 ; cha 𐎨
U+006A U+0061 <> U+103A9 ; ja 𐎩
U+006A U+0069 <> U+103AA ; ji 𐎪
U+0074 U+0061 <> U+103AB ; ta 𐎫
U+0074 U+0075 <> U+103AC ; tu 𐎬
U+0064 U+0061 <> U+103AD ; da 𐎭
U+0064 U+0069 <> U+103AE ; di 𐎮
U+0064 U+0075 <> U+103AF ; du 𐎯
U+0074 U+0068 U+0061 <> U+103B0 ; tha 𐎰
U+0070 U+0061 <> U+103B1 ; pa 𐎱
U+0062 U+0061 <> U+103B2 ; ba 𐎲
U+0066 U+0061 <> U+103B3 ; fa 𐎳
U+006E U+0061 <> U+103B4 ; na 𐎴
U+006E U+0075 <> U+103B5 ; nu 𐎵
U+006D U+0061 <> U+103B6 ; ma 𐎶
U+006D U+0069 <> U+103B7 ; mi 𐎷
U+006D U+0075 <> U+103B8 ; mu 𐎸
U+0079 U+0061 <> U+103B9 ; ya 𐎹
U+0076 U+0061 <> U+103BA ; va 𐎺
U+0076 U+0069 <> U+103BB ; vi 𐎻
U+0072 U+0061 <> U+103BC ; ra 𐎼
U+0072 U+0075 <> U+103BD ; ru 𐎽
U+006C U+0061 <> U+103BE ; la 𐎾
U+0073 U+0061 <> U+103BF ; sa 𐎿
U+007A U+0061 <> U+103C0 ; za 𐏀
U+0073 U+0068 U+0061 <> U+103C1 ; sha 𐏁
U+0073 U+0073 U+0061 <> U+103C2 ; ssa 𐏂
U+0068 U+0061 <> U+103C3 ; ha 𐏃
U+0061 U+0075 U+0072 <> U+103C8 ; aur 𐏈
U+0061 U+0075 U+0072 U+0032 <> U+103C9 ; aur2 𐏉
U+0061 U+0075 U+0072 U+0033 <> U+103CA ; aur3 𐏊
U+0078 U+0078 <> U+103CB ; xx 𐏋
U+0064 U+0061 U+0068 <> U+103CC ; dah 𐏌
U+0064 U+0061 U+0068 U+0032 <> U+103CD ; dah2 𐏍
U+0062 U+0061 U+0067 U+0061 <> U+103CE ; baga 𐏎
U+0062 U+0075 U+0075 <> U+103CF ; buu 𐏏
U+0064 U+0069 U+0076 <> U+103D0 ; div 𐏐
U+0031 <> U+103D1 ; 1 𐏑
U+0032 <> U+103D2 ; 2 𐏒
U+0031 U+0030 <> U+103D3 ; 10 𐏓
U+0032 U+0030 <> U+103D4 ; 20 𐏔
U+0031 U+0030 U+0030 <> U+103D5 ; 100 𐏕
oldpersian-to-latine (latin with diacritics and long vowels; versions a,b,c,d do slightly different transliteration schemes)
; TECkit mapping for TeX input conventions <-> Unicode characters
LHSName "UNICODE"
RHSName "oldpersian-to-latin"
pass(Unicode)
; ligatures from Knuth's original CMR fonts
U+002D U+002D <> U+2013 ; -- -> en dash
U+002D U+002D U+002D <> U+2014 ; --- -> em dash
U+0027 <> U+2019 ; ' -> right single quote
U+0027 U+0027 <> U+201D ; '' -> right double quote
U+0022 > U+201D ; " -> right double quote
U+0060 <> U+2018 ; ` -> left single quote
U+0060 U+0060 <> U+201C ; `` -> left double quote
U+0021 U+0060 <> U+00A1 ; !` -> inverted exclam
U+003F U+0060 <> U+00BF ; ?` -> inverted question
; additions supported in T1 encoding
U+002C U+002C <> U+201E ; ,, -> DOUBLE LOW-9 QUOTATION MARK
U+003C U+003C <> U+00AB ; << -> LEFT POINTING GUILLEMET
U+003E U+003E <> U+00BB ; >> -> RIGHT POINTING GUILLEMET
;U+002D <> U+002D ; space
U+103A4 U+103A2 <> U+006B U+0075 U+0301 ; kuu>ku'
U+103C3 U+103A1 <> U+0068 U+0069 ; hai > hi
U+103B4 U+103A1 <> U+006E U+0069 ; nai>ni
U+103B4 U+103A2 <> U+006E U+0075 ; nau>nu
U+103C1 U+103A1 <> U+0161 U+0069 ; shai>si
U+103A7 U+103A0 <> U+0078 U+0061 U+0301 ; xa a > xa'
U+103A0 <> U+0061 ; a
U+103A1 <> U+0069 ; i
U+103A2 <> U+0075 ; u
U+103A3 <> U+006B U+0061 ; ka
U+103A4 <> U+006B U+0075 ; ku
U+103A5 <> U+0067 U+0061 ; ga
U+103A6 <> U+0067 U+0075 ; gu
U+103A7 <> U+0078 U+0061 ; xa
U+103A8 <> U+00E7 U+0061 ; ça
U+103A9 <> U+006A U+0061 ; ja
U+103AA <> U+006A U+0069 ; ji
U+103AB <> U+0074 U+0061 ; ta
U+103AC <> U+0074 U+0075 ; tu
U+103AD <> U+0064 U+0061 ; da
U+103AE <> U+0064 U+0069 ; di
U+103AF <> U+0064 U+0075 ; du
U+103B0 <> U+03B8 U+0061 ; θa
U+103B1 <> U+0070 U+0061 ; pa
U+103B2 <> U+0062 U+0061 ; ba
U+103B3 <> U+0066 U+0061 ; fa
U+103B4 <> U+006E U+0061 ; na
U+103B5 <> U+006E U+0075 ; nu
U+103B6 <> U+006D U+0061 ; ma
U+103B7 <> U+006D U+0069 ; mi
U+103B8 <> U+006D U+0075 ; mu
U+103B9 <> U+0079 U+0061 ; ya
U+103BA <> U+0076 U+0061 ; va
U+103BB <> U+0076 U+0069 ; vi
U+103BC <> U+0072 U+0061 ; ra
U+103BD <> U+0072 U+0075 ; ru
U+103BE <> U+006C U+0061 ; la
U+103BF <> U+0073 U+0061 ; sa
U+103C0 <> U+007A U+0061 ; za
U+103C1 <> U+0161 U+0061 ; ša
U+103C2 <> U+015F U+0061 ; şa
U+103C3 <> U+0068 U+0061 ; ha
U+103C8 <> U+0061 U+0075 U+0072 ; aur
U+103C9 <> U+0061 U+0075 U+0072 ; aur2
U+103CA <> U+0061 U+0075 U+0072 ; aur3
U+103CB <> U+0078 U+0078 ; xx
U+103CC <> U+0064 U+0061 U+0068 ; dah
U+103CD <> U+0064 U+0061 U+0068 ; dah2
U+103CE <> U+0062 U+0061 U+0067 ; baga
U+103CF <> U+0062 U+0075 U+0075 ; buu
U+103D0 <> U+0020 ;U+0044 U+0049 U+0056 U+005C U+002D U+0020 ; div 64 69 76 DIV 44 49 56
U+103D1 <> U+0031 ; 1
U+103D2 <> U+0032 ; 2
U+103D3 <> U+0031 U+0030 ; 10
U+103D4 <> U+0032 U+0030 ; 20
U+103D5 <> U+0031 U+0030 U+0030 ; 100
Hieroglyph maps are too big to fit all of them in here, but the first part looks like:
gardnernum-to-hieroglyph (the A001 -> U+13000 version)
; TECkit mapping for TeX input conventions <-> Unicode characters
LHSName "Gardiner-to-Hieroglyph"
RHSName "UNICODE"
pass(Unicode)
; ligatures from Knuth's original CMR fonts
U+002D U+002D <> U+2013 ; -- -> en dash
U+002D U+002D U+002D <> U+2014 ; --- -> em dash
U+0027 <> U+2019 ; ' -> right single quote
U+0027 U+0027 <> U+201D ; '' -> right double quote
U+0022 > U+201D ; " -> right double quote
U+0060 <> U+2018 ; ` -> left single quote
U+0060 U+0060 <> U+201C ; `` -> left double quote
U+0021 U+0060 <> U+00A1 ; !` -> inverted exclam
U+003F U+0060 <> U+00BF ; ?` -> inverted question
; additions supported in T1 encoding
U+002C U+002C <> U+201E ; ,, -> DOUBLE LOW-9 QUOTATION MARK
U+003C U+003C <> U+00AB ; << -> LEFT POINTING GUILLEMET
U+003E U+003E <> U+00BB ; >> -> RIGHT POINTING GUILLEMET
; Egyptian hieroglyphs
U+0041 U+0030 U+0030 U+0031 <> U+13000
U+0041 U+0030 U+0030 U+0032 <> U+13001
U+0041 U+0030 U+0030 U+0033 <> U+13002
U+0041 U+0030 U+0030 U+0034 <> U+13003
U+0041 U+0030 U+0030 U+0035 <> U+13004
U+0041 U+0030 U+0030 U+0035 U+0041 <> U+13005
U+0041 U+0030 U+0030 U+0036 <> U+13006
U+0041 U+0030 U+0030 U+0036 U+0041 <> U+13007
U+0041 U+0030 U+0030 U+0036 U+0042 <> U+13008
U+0041 U+0030 U+0030 U+0037 <> U+13009
U+0041 U+0030 U+0030 U+0038 <> U+1300A
U+0041 U+0030 U+0030 U+0039 <> U+1300B
U+0041 U+0030 U+0031 U+0030 <> U+1300C
U+0041 U+0030 U+0031 U+0031 <> U+1300D
U+0041 U+0030 U+0031 U+0032 <> U+1300E
U+0041 U+0030 U+0031 U+0033 <> U+1300F
etc
and gardnernum-to-hieroglyph2.map (the A1 -> U+13000, much easier to type):
; TECkit mapping for TeX input conventions <-> Unicode characters
LHSName "Gardiner-to-Hieroglyph2"
RHSName "UNICODE"
pass(Unicode)
; ligatures from Knuth's original CMR fonts
U+002D U+002D <> U+2013 ; -- -> en dash
U+002D U+002D U+002D <> U+2014 ; --- -> em dash
U+0027 <> U+2019 ; ' -> right single quote
U+0027 U+0027 <> U+201D ; '' -> right double quote
U+0022 > U+201D ; " -> right double quote
U+0060 <> U+2018 ; ` -> left single quote
U+0060 U+0060 <> U+201C ; `` -> left double quote
U+0021 U+0060 <> U+00A1 ; !` -> inverted exclam
U+003F U+0060 <> U+00BF ; ?` -> inverted question
; additions supported in T1 encoding
U+002C U+002C <> U+201E ; ,, -> DOUBLE LOW-9 QUOTATION MARK
U+003C U+003C <> U+00AB ; << -> LEFT POINTING GUILLEMET
U+003E U+003E <> U+00BB ; >> -> RIGHT POINTING GUILLEMET
; Egyptian hieroglyphs
U+0041 U+0031 <> U+13000
U+0041 U+0032 <> U+13001
U+0041 U+0033 <> U+13002
U+0041 U+0034 <> U+13003
U+0041 U+0035 <> U+13004
U+0041 U+0035 U+0041 <> U+13005
U+0041 U+0036 <> U+13006
U+0041 U+0036 U+0041 <> U+13007
U+0041 U+0036 U+0042 <> U+13008
U+0041 U+0037 <> U+13009
U+0041 U+0038 <> U+1300A
U+0041 U+0039 <> U+1300B
U+0041 U+0031 U+0030 <> U+1300C
U+0041 U+0031 U+0031 <> U+1300D
U+0041 U+0031 U+0032 <> U+1300E
U+0041 U+0031 U+0033 <> U+1300F
U+0041 U+0031 U+0034 <> U+13010
U+0041 U+0031 U+0034 U+0041 <> U+13011
U+0041 U+0031 U+0035 <> U+13012
U+0041 U+0031 U+0036 <> U+13013
U+0041 U+0031 U+0037 <> U+13014
U+0041 U+0031 U+0037 U+0041 <> U+13015
U+0041 U+0031 U+0038 <> U+13016
U+0041 U+0031 U+0039 <> U+13017
U+0041 U+0032 U+0030 <> U+13018
U+0041 U+0032 U+0031 <> U+13019
U+0041 U+0032 U+0032 <> U+1301A
U+0041 U+0032 U+0033 <> U+1301B
U+0041 U+0032 U+0034 <> U+1301C
U+0041 U+0032 U+0035 <> U+1301D
U+0041 U+0032 U+0036 <> U+1301E
U+0041 U+0032 U+0037 <> U+1301F
etc
longs
at the end of a word (according to Wikipedia). I know how to set this up for a traditional TeX font (without needing to make anything active), but I don't know if you can do it this way for XeTeX of if you'd need something similar to tex.stackexchange.com/questions/217943/… (but forward-looking).