13

Is there a way to define some extra kerning around the en-dash (Unicode) or -- (TeX ligature), when it is surrounded by digits in XeTeX? For I can use \XeTeXinterchartoks, but this doesn’t work for --.

% !TeX program = xelatex
\documentclass{article}

\usepackage{fontspec}

\XeTeXinterchartokenstate = 1

\newXeTeXintercharclass \enDashCharacterClass
\newXeTeXintercharclass \digitsCharacterClass

\XeTeXcharclass `– \enDashCharacterClass
%\XeTeXcharclass `- \enDashCharacterClass

\XeTeXcharclass `0 \digitsCharacterClass
\XeTeXcharclass `1 \digitsCharacterClass
\XeTeXcharclass `2 \digitsCharacterClass
\XeTeXcharclass `3 \digitsCharacterClass
\XeTeXcharclass `4 \digitsCharacterClass
\XeTeXcharclass `5 \digitsCharacterClass
\XeTeXcharclass `6 \digitsCharacterClass
\XeTeXcharclass `7 \digitsCharacterClass
\XeTeXcharclass `8 \digitsCharacterClass
\XeTeXcharclass `9 \digitsCharacterClass

% adding dots for testing only
\XeTeXinterchartoks \digitsCharacterClass \enDashCharacterClass {.\kern0.05em.}
\XeTeXinterchartoks \enDashCharacterClass \digitsCharacterClass {.\kern0.05em.}

\begin{document}
\textbf{works}

test – test

0 – 0

0–1–2–3–4–5–6–7–8–9–0

\bigskip
\textbf{doesn't work}

test -- test

0 -- 0

0--1--2--3--4--5--6--7--8--9--0

\bigskip
\textbf{should not be kerned}

42-storey building
\end{document}

This gives the following result: Only the en-dashes entered as real en-dashes () are kerned, the ones entered as TeX ligature (--) not:

first result

If we uncomment one line in the MWE and ad the hyphen (-) to the en-dash class the ligatures (--) get kerned too. But unfortunately this also affects single hyphens which should not be kerned:

second result

Note: The dots are only for testing.

5
  • From the XeTeX mailing list I git the answer to simply add the hype to the class too but this affects also cases like digit-word-compounds … [see edit]
    – Tobi
    Jul 3, 2016 at 8:14
  • It is not clear what you mean by works/doesn't work as the two paragraphs give the same output. Presumably to achieve what you want you'll need also to use \@ifnextchar. Jul 4, 2016 at 10:06
  • @BrunoLeFloch: Sorry … that was due to my edit, when incorporating a solution attempt. I edited the question again to clarify this … :-)
    – Tobi
    Jul 4, 2016 at 14:01
  • Would a LuaLaTeX-based solution be of interest, or does it have to be XeLaTeX-based?
    – Mico
    Aug 6, 2016 at 18:03
  • @Mico: This should become part of a class. That is at the moment only planned for XeTeX. But a LuaTeX solution would be nice to have here on TeX.SX even if its “only” for the users searching/finding this question …
    – Tobi
    Aug 6, 2016 at 20:44

2 Answers 2

10
+100

I don't think that it is possible intercharclass, as the ligature from -- to endash is built later. What you can do is add a thin space through a mapping.

E.g. with this mapping you get a small space between 1 and the dashes:

; TECkit mapping for TeX input conventions <-> Unicode characters

LHSName "kerndash"
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

pass(Unicode)
U+0031 U+2013 <>  U+0031 U+2009 U+2013
U+0031 U+2014 <>  U+0031 U+2009 U+2014

This answer shows how to compile it Change em-dash character in an OpenType font with xetex

Test document:

\documentclass{article}
\usepackage{fontspec}
\setmainfont{Arial}
\setsansfont[Mapping=kerndash]{Arial}
\begin{document}
1– 1-- 1— 1---

{\sffamily 1– 1-- 1— 1---}

\end{document}

enter image description here

3
  • Thats an interesting approach! But in that case the space must be a unicode char and isn’t completly customizable, is it? E.g. what if I want the space to be exactly 0.1234em?
    – Tobi
    Aug 6, 2016 at 20:43
  • Imho you can only insert glyphs. If you want a fully customizable engine use luatex. Aug 10, 2016 at 13:11
  • hm … ok. or this class I have to stick to XeTeX.
    – Tobi
    Aug 10, 2016 at 13:34
11

(The OP has asked primarily for a XeLaTeX-based approach. However, he has also encouraged the submission of a LuaLaTeX-based solution.)

Here's a LuaLaTeX-based solution. It works with en- and em-dashes encoded either as -- and --- or as and , respectively. LaTeX macros are provided to switch the operation of the Lua function that performs the insertions of the extra kerns (at the stage of the callback process_input_buffer, i.e., very early during the processing phase) on and off, as needed. The amount of extra kerning that inserted between the numbers and the en/em-dashes can be modified via a LaTeX macro called \kset, e.g., \kset{0.07em}. (Restore the default amount of kerning by executing \kset{0.07em}.)

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{fontspec}

\usepackage{luacode}
\begin{luacode}
kval = "0.05em" -- Set default value of amount of extra kerning
function kern_dashes ( s )
  s = string.gsub ( s , "(%d)%-%-" , "%1\\kern"..kval.."--" )
  s = string.gsub ( s , "%-%-(%d)" , "--\\kern"..kval.."%1" ) 
  s = unicode.utf8.gsub ( s, "(%d)–" , "%1\\kern"..kval.."–" )
  s = unicode.utf8.gsub ( s, "–(%d)" , "–\\kern"..kval.."%1" ) 
  s = unicode.utf8.gsub ( s, "(%d)—" , "%1\\kern"..kval.."—" )
  s = unicode.utf8.gsub ( s, "—(%d)" , "—\\kern"..kval.."%1" ) 
  return s 
end
\end{luacode}
\newcommand{\extrakernOn}{\directlua{
    luatexbase.add_to_callback (   
    "process_input_buffer" , kern_dashes , "kern_dashes" )}}
\newcommand{\extrakernOff}{\directlua{
    luatexbase.remove_from_callback (   
    "process_input_buffer" , "kern_dashes" )}}
\AtBeginDocument{\extrakernOn} % switch function on by default

% Macro to set the amount of extra kerning
\newcommand\kset[1]{\directlua{kval=\luastring{#1}}} 

\begin{document}
\obeylines % just for this example

3--5, 3---5
3–5, 3—5

\extrakernOff % switch off automatic insertion of extra kerns
3--5, 3---5
3–5, 3—5

\extrakernOn% switch automatic insertion of extra kerns back on
\kset{.2em} % quadruple the amount of extra kerning
3--5, 3---5
3–5, 3—5

\end{document}

Addendum: In the preceding example, the Lua function kern_dashes is written so that extra kerns are inserted before the start of en- and em-dashes (assuming they're immediately preceded by a digit) or after the end of en- and em-dashes (assuming they're immediately followed by a digit). If the kerns should be inserted only if the en- and em-dashes are both preceded and followed by digits, the following code would be more appropriate:

function kern_dashes ( s )
  s = string.gsub ( s , "(%d)%-%-(%d)"   ,  "%1\\kern"..kval.."--\\kern"..kval.."%2" )
  s = string.gsub ( s , "(%d)%-%-%-(%d)" ,  "%1\\kern"..kval.."---\\kern"..kval.."%2" )
  s = unicode.utf8.gsub ( s , "(%d)–(%d)" , "%1\\kern"..kval.."–\\kern"..kval.."%2" )
  s = unicode.utf8.gsub ( s , "(%d)—(%d)" , "%1\\kern"..kval.."—\\kern"..kval.."%2" )
  return s 
end

You must log in to answer this question.

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