# Output hyphen as en-dash in macro

In my thesis I will include a fair number of tags (morphological tags, in case it matters) that are fixed-width character strings like this: ab-c--d, where dashes denote NULL fields. I'd like to define a macro \msd that takes such a tag and outputs it with en-dashes for the NULL fields.

As far as I can make out, this macro needs to do two things:

1. Disable the double-hyphen and triple-hyphen ligatures (to avoid weirdness when two NULL fields are adjacent)
2. The actual TeXnical jiggery-pokery required to render hyphens as en-dashes

The details of how I'd do this elude me, unfortunately. Could someone help me out with this, or point me in the right direction?

-
Is it practiable to find and replace on the tags before inclusion and just replace the hypen character with a macro \null say, which then is defined as an en-dash? This would certainly be a simple and safe solution, if practical... – Seamus Jan 26 '11 at 13:10
Another option might be to typeset using typewriter font: \newcommand*\msd{}\let\msd\texttt. – Bruno Le Floch Jan 26 '11 at 18:44

Here is a straightforward latex solution. It may behave oddly, though, if you feed unexpected stuff to it, such as brace delimited material (such as, say, \msd{ab{-b-c}d}).

\documentclass{minimal}
\newcommand{\msd}[1]{\msdhelper#1\relax}
\newcommand{\msdhelper}[1]
{\ifx\relax#1\else
\ifx-#1--{}\else#1\fi
\expandafter\msdhelper\fi}
\begin{document}
\msd{ab-c--d}
\end{document}

-
In the end, I went with a variant on this. As Alan Munn pointed out, there's no space around the en-dashes, so explicit space is needed. I went with 1pt of space, and an mbox around the whole ting, so that it won't be broken up. – arnsholt Mar 26 '11 at 16:50

There's a simple solution to your problem: just encode your source file as UTF-8 and change all the null field markers to the actual en-dash in your source.

However, I don't think this will achieve the formatting you actually want, since when you put two en-dashes together, they will not have any space between them (unlike the hyphen characters.) So probably what you need is a bit more complicated, since you need to add some space after each en-dash to show the null fields as individual elements.

So here's another solution using XeLaTeX: create a custom map file which maps the hyphen into an en-dash with a non-breaking space. The following instructions work on a Mac or Linux machine; the same thing can be done in Windows but I don't know how, although you can get directions in the link below.

First, dowload and install the TECkit software from SIL:

Next, make the following map file (plain text file, named hyphen-dash.map). This file maps '-' into an en-dash+non-breaking space.

; Hyphen to emdash mapping file for XeTeX
; hyphen-dash.map
;
LHSName "hyphen-dash"
RHSName "UNICODE"
pass(Unicode)

U+002D  <>  U+2013 U+00A0   ; "-" -> "– "


Next, compile this file using the following command from the command line:

teckit_compile hyphen-dash.map -o hyphen-dash.tec


Copy the hyphen-dash.tec file to your local texmf folder in fonts/misc/xetex

Now you can compile the following xelatex document:

% !TEX TS-program = XeLaTeX
\documentclass{article}
\usepackage{fontspec}
\pagestyle{empty}
\setmainfont[Mapping=tex-text]{Charis SIL}
\newfontfamily\glossfont[Mapping=hyphen-dash]{Charis SIL}
\newcommand{\formatgloss}[1]{{\glossfont#1}}
\begin{document}
Without the hyphen mapping: regular hyphens and dashes:

a-b--c---d

What happens when you put two en-dashes directly together:

a––

Now with the mapping file enabled:

\formatgloss{a-b--c----d}

This solution can be used inside other macros:

\textit{\formatgloss{a-b--c----d}}
\end{document}


Output here:

-

The following TeXnical jiggery-pokery seems to work:

\documentclass{article}
\begingroup
\catcode-=\active
\aftergroup\newcommand
\aftergroup-
\endgroup
{--\relax}
\newcommand\msd{\begingroup\catcode-=\active\msdhelper}
\newcommand\msdhelper[1]{#1\endgroup}
\begin{document}
test \msd{ab-c--d} test-case
\end{document}


Inside the \msd macro, the - is made active (and produces the en-dash), but the usual - is restored afterwards. This solution can cause trouble if other packages try similar trickery with making - active.

-
This will work fine when \msd{ab-c--d} is encountered at top-level, but not if this is encountered as an argument to some other macro (since the catcodes will be fixed and cannot be changed, except perhaps by some etex hackery). – Harald Hanche-Olsen Jan 26 '11 at 15:36

And a LaTeX3 answer as well: we go through the argument token by token using \tl_map_function:nN, and we replace every character - by the token list --\relax. Note that this implementation gets confused by braced things, e.g. \msd{a{bc}d} will fail.

\documentclass{minimal}
\usepackage{expl3}
\usepackage{xparse}
\begin{document}
\ExplSyntaxOn
\cs_new:Npn \msd #1 {
\tl_map_function:nN {#1} \msd_convert_dash:n
}
\cs_new:Npn \msd_convert_dash:n #1 {
\token_if_eq_charcode:NNTF - #1 {\texttt{-}} {#1}
}
\ExplSyntaxOff

% Tests
\msd{a--b-c}
\msd{a-bc}
% It is expandable:
\edef\foo{\msd{a-b---c}}
\foo

\end{document}


EDIT: Alan Munn is right about two dashes together looking ugly. I replaced by a \texttt{-} in my solution.

-
There is a \tl_replace_all_in:Nnn function that probably makes this a bit easier. – Will Robertson Jan 27 '11 at 5:11
@Will: \tl_replace_all_in:Nnn seems to require the argument to already be inside a token list. Putting it there would be unexpandable. – Bruno Le Floch Jan 27 '11 at 6:30