5

I'm working with a display font that is missing many common characters, including parenthesis, em-dash, and true ``directional quotes''.

I'd like a straightfoward way to replace these with matching characters set in another font when encountered. A general "if the primary font is missing this character, use this other font" would work, but I can identify all of the characters I care about. I do not need change the character; if the missing character is, say "(", it will be ( in the fallback font. I'm only using the font in limited circumstances (\chapter and \section in memoir) which may may the problem easier or harder. Similarly, all fonts involved are TrueType/OpenType.

newunicodechar and ucharclasses seem promising, but the former won't meddle with ASCII characters and the latter only works on entire Unicode blocks.

XeTeX's interchar class mechanism seems promising, and is my plan B. But I'd prefer something a bit more portable, if only between XeLaTeX and LuaLaTex.

Minimal Working Example, relying on the free Cyberfunk font.

\documentclass{article}
\usepackage{fontspec}
\begin{document}
``Dr. J---/Mr. H---'s (Missing Glyph) Day''

\fontspec{Cyberfunk}``Dr. J---/Mr. H---'s (Missing Glyph) Day''
\end{document}

enter image description here

I can provide a longer, more realistic example of how I'm using it with memoir if that's helpful; but it was a lot longer.

1
  • Making ( active (which is what \newunicodechar would do) is a sure way to break other constructs where ( is expected to be the regular one. Doing a replacement before passing the titles to the actual macros seems the solution with the least impact.
    – egreg
    Jan 25, 2017 at 8:11

1 Answer 1

1

Here you can set up a token cycle to search for the missing glyphs and replace them with glyphs of an alternate font, here taken as Calibri.

Here, I have taken the liberty of searching for and replacing the following glyphs/strings: (, ), , ', /, -, --, and ---.

Note that changing catcodes inside of the token cycle can't be easily accomplished, since the tokens are scanned with the current catcodes before they are executed. This affects verbatim blocks, for example.

\documentclass{article}
\usepackage{fontspec,tokcycle}
\newif\ifemdash
\newif\ifendash
\newcommand\dashtest{\emdashfalse\endashfalse\tcpeek\Q
  \ifx-\Q\tcpop\Q\tcpeek\QQ\ifx-\QQ\tcpop\QQ\emdashtrue\else
  \endashtrue\fi\fi
}
\Characterdirective{%
  \ifx(#1\addcytoks{{\setmainfont{Calibri}(}}\else
  \ifx)#1\addcytoks{{\setmainfont{Calibri})}}\else
  \ifx`#1\addcytoks{{\setmainfont{Calibri}`}}\else
  \ifx'#1\addcytoks{{\setmainfont{Calibri}'}}\else
  \ifx/#1\addcytoks{{\setmainfont{Calibri}/}}\else
  \ifx-#1\dashtest
    \ifemdash\addcytoks{{\setmainfont{Calibri}---}}\else
    \ifendash\addcytoks{{\setmainfont{Calibri}--}}\else
    \addcytoks{{\setmainfont{Calibri}-}}\fi\fi
  \else
  \addcytoks{#1}\fi\fi\fi\fi\fi\fi
}
\begin{document}
``Dr. J---/Mr. H---'s (Missing Glyph) Day''

Endash -- and Hyphen -

\setmainfont{Cyberfunk}
\tokencyclexpress
``Dr. J---/Mr. H---'s (Missing Glyph) Day''

Endash -- and Hyphen -
\endtokencyclexpress
\end{document}

enter image description here

The processed tokens of the cycle are buffered and output at the conclusion of the cycle. If the token cycle is very large (encompassing the whole document, for example), and one is worried about exceeding an internal buffer size, one can instruct the token cycle to clear the buffer after each ungrouped \par, by adding a \Macrodirective, as follows:

\Macrodirective{
  \addcytoks{#1}\ifnum\tcdepth=0
    \ifx\par#1\the\cytoks\cytoks{}\fi
  \fi% CLEARS BUFFER ON UNGROUPED \par
}
2
  • Verbatim can be partially handled by scantokens the result, as long as there's no dashes inside it.
    – user202729
    Dec 27, 2021 at 5:24
  • @user202729 indeed it can. Also, if one goes through the effort, the token cycle can change catcodes in the middle of its process, through the use of escape tokens, or with more difficulty, examining the input stream for words like verbatim. Dec 27, 2021 at 13:13

You must log in to answer this question.

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