# Defining \xthinspace: Thin space only if not followed by certain characters

Following this 2005 thread from the XeTeX list, I’ve defined a \spaceddash command and assigned it to the Unicode em-dash character U+2014 “—”:

\documentclass{minimal}
\usepackage[utf8]{inputenc}
\DeclareRobustCommand{\spaceddash}%
{\unskip\nobreak\thinspace\textemdash\thinspace\ignorespaces}
\DeclareUnicodeCharacter{2014}{\spaceddash}

\begin{document}
meow — meow

meow—meow

— meow

meow —.
\end{document}

The document this produces looks something like this:

meow — meow
meow — meow
— meow
meow — .

Notice the thin-space between the em-dash on the last line and the period afterward—I’d like to get rid of it.

Following the example of xspace & xpunctuate, I’m trying to define a sort of \xthinspace command, one that will insert the \thinspace except if the dash is followed by certain punctuation marks (e.g., period, comma, close-parenthesis, close-quote).

-

Here's a possibility using expl3. The test gobbles spaces and then checks whether the following token appears in the exceptions list. If not, it applies \thinspace.

\documentclass{article}
\usepackage[utf8]{inputenc}

\usepackage{newunicodechar,xparse}

% The following is equivalent to \DeclareUnicodeCharacter{2014}{...}
\newunicodechar{—}{\spaceddash} % write only \spaceddash in aux files
\NewDocumentCommand{\spaceddash}{%
\ifvmode\leavevmode\else\unskip\nobreak\thinspace\fi
\textemdash\xthinspace}

\ExplSyntaxOn
\NewDocumentCommand{\xthinspace}{ } { \xths_main: }
{
\tl_gput_right:Nn \g_xths_exceptions_tl { #1 }
}
\cs_new_protected:Npn \xths_main:
{
\bool_set_true:N \l_xths_apply_bool
\peek_catcode_ignore_spaces:NF \c_space_token { \xths_check: }
}
\cs_new_protected:Npn \xths_check:
{
\tl_map_inline:Nn \g_xths_exceptions_tl
{
\token_if_eq_charcode:NNT ##1 \l_peek_token
{\bool_set_false:N \l_xths_apply_bool \prg_map_break: }
}
\bool_if:NT \l_xths_apply_bool { \thinspace }
}
\tl_new:N \g_xths_exceptions_tl
\ExplSyntaxOff

\begin{document}
meow—meow

meow—.

meow— .
\end{document}

Try it with \hspace{1cm} instead of \thinspace if you want to verify it works. A limitation: if the — is followed by a macro that expands to a comma, a period or a closed parenthesis, the test will fail.

-
 Definition of \spaceddash is missing the argument specifier, also the \unskip\nobreak & \ignorespaces; but with those changes, this does exactly what I was looking for. Thank you. – J. C. Salomon Jun 13 '12 at 4:05 Also, \kern1em is more appropriate than \hspace for testing, because it won’t leave space at line’s beginning (\thinspace is just \kern.1666em) (though it plays funny games with vertical kerning at the start of a paragraph). After defining \dashspace to \kern1em (for testing) or \thinspace, my definition was \NewDocumentCommand{\spaceddash}{ }{\unskip\nobreak\ifhmode\dashspace\fi\textemdash\xthinspace\ignorespaces} – J. C. Salomon Jun 13 '12 at 4:11 @J.C.Salomon I've added the test for vertical mode; \xthinspace\ignorespaces is an error, as \xthinspace has \ignorespaces after it and so the test it performs is useless. – egreg Jun 13 '12 at 6:26

\@ifnextchar (thanks @egreg) is your friend here:

\DeclareRobustCommand{\spaceddash}%
{\unskip\nobreak\thinspace\textemdash\gobblespaces}
\makeatletter\def\gobblespaces{\@ifnextchar.\relax\thinspace}\makeatother

\@ifnextchar gobbles any intervening space tokens. It compares the first non-space token found to its first argument ("." here) and executes the first macro if they are the same ("\relax'"); otherwise, it executes the second macro ("\thinspace'").

Obviously, this could be generalized to look for any number of tokens. I'm sure xspace does something similar.

A full MWE is:

\documentclass{minimal}
\usepackage[utf8]{inputenc}
\DeclareRobustCommand{\spaceddash}%
{\unskip\nobreak\thinspace\textemdash\gobblespaces}
\makeatletter\def\gobblespaces{\@ifnextchar.\relax\thinspace}\makeatother
\DeclareUnicodeCharacter{2014}{\spaceddash}

\begin{document}
meow — meow

meow—meow

— meow

meow —.
\end{document}

And the resulting document looks like:

-
 There seems to be a spacing issue on the right for the first and third case. – Peter Grill Jun 12 '12 at 6:22