You can possibly do it with \verb
. But let's look what happens with your attempt. In
\newcommand{\mon}[1]{%
\mbox{%
\texttt{%
\protect\detokenize{#1}%
}%
}%
}
there is a misplaced \protect
that however does nothing bad. The problem is that TeX sees #
6 before the “detokenization” actually takes place and this results in a bad token list to be passed as argument to \texttt
. Indeed, if you use \ttfamily
the problem is solved:
\newcommand{\mon}[1]{%
\mbox{%
\ttfamily
\detokenize{#1}%
}%
}
A different strategy could be performing \detokenize
before doing anything else:
\newcommand{\mon}[1]{%
\expandafter\monAUX\expandafter{\detokenize{#1}}%
}
\newcommand{\monAUX}[1]{%
\mbox{\texttt{#1}}%
}
This however doesn't solve the problem with F#
, because you'll clearly see the #
is doubled. That's part of how \detokenize
works (and TeX is designed), so for this particular application I'm afraid \verb
is the solution. Or some less heavy trick that changes the category code of #
(so it can't be used in the argument to another command).
A different approach might be with expl3
:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\tl_const:Nx \c_ledfan_doublehash_tl { \tl_to_str:n { # } }
\tl_new:N \l_ledfan_mon_tl
\NewDocumentCommand{\mon}{m}
{
\tl_set:Nf \l_ledfan_mon_tl { \tl_to_str:n { #1 } }
\tl_replace_all:NVV \l_ledfan_mon_tl \c_ledfan_doublehash_tl \c_hash_str
\texttt{ \tl_use:N \l_ledfan_mon_tl }
}
\cs_generate_variant:Nn \tl_replace_all:Nnn { NVV }
\ExplSyntaxOff
\begin{document}
\mon{F#}
\mon{C##}
\end{document}
The assumption is that any ##
in the token list we build comes from \tl_to_str:n
(which is \detokenize
in disguise) applied to a #
6 token, so it's replaced by a single one.

This has still some limitations, because it can't go in the argument of any argument that performs some \protected@edef
or \protected@write
; for instance \textbf
and similar commands or \section
, \caption
and friends.
\verb|F#|
– egreg Jan 24 '16 at 8:47