How can I add extra kerning around -- (en-dash) in XeTeX

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


(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