# macro names with special characters

Is it possible to create macro names with special characters in it?

I would like to creates some macro's that have names like \s1.4 and also to be able to use them like \s1.4Test where Test is not treated as part of the macro name(basically anything after the float is excluded as being part of the macro name)

Basically this is to avoid having to do \s{1.4}Text which adds two extra characters and for my purposes \s1.4 has no issues(I will never have things like \s1.x and expect x not to be part of the macro so there will never be any ambiguity).

BTW, I'm defining these using a foreach:

\makeatletter
\foreach \m in {1.1, 2.2}
{
\expandafter\protected@xdef\csname s\m\endcsname{$_\mathbf{\m}$}
}
\makeatother

-
Well, there is: \expandafter\def\csname s1.4\endcsname or the shortcut \@namedef{s1.4} (or etoolbox' \csdef{s1.4}). Another question is if it's wise to do that. –  cgnieder Aug 22 '12 at 11:42
"no" is the most useful answer. Technically the answer to your question is "yes" you can go \catcode'\1=11 \catcode'\.=11 \catcode'\4=11 \def\s1.4Test{...} but you don't want to do that (as then 1 and 4 would not be numbers so you could not for example say \hspace{14pt} –  David Carlisle Aug 22 '12 at 11:43
@cgnieder it is wise for me, as I said, there will be no ambiguity. My document is not complex and never will be. When I use my code(which should be virtually identical to yours), I get an undefined macro as it is not associating the number. When I call \s1.4 it gives an error "undefined control sequence" after \s –  AbstractDissonance Aug 22 '12 at 11:50
You cannot use \s1.4 then. This would call the macro \s followowed by the number 1 (assuming you haven't changed catcodes). Try \csname s1.4\endcsname or \@nameuse{s1.4} instead. –  cgnieder Aug 22 '12 at 11:53
@cgnieder Well, it looks like David found a solution. Not sure how it works but it seems to work just fine. –  AbstractDissonance Aug 22 '12 at 11:57
show 1 more comment

plain TeX example but it would work in latex, \s is simpler but requires a . \t is more complicated but accepts an integer.

\def\s#1.{%
\def\tmp{#1.}%
\afterassignment\xxs\count0= }

\def\xxs{\csname s\tmp\the\count0\endcsname}

%%%%%%%%%%%%%%%%%%%

\def\t{\afterassignment\xxt\count0= }

\def\xxt{\futurelet\tmp\xxxt}

\def\xxxt{%
\if.\noexpand\tmp
\expandafter\xxxxt
\else
\csname s\the\count0\expandafter\endcsname
\fi}

\def\xxxxt.{\afterassignment\xtx\count2= }

\def\xtx{\csname s\the\count0.\the\count2\endcsname}

%%%%%%%%%%%%%%%%%%%

\expandafter\def\csname s1.4\endcsname{one point four }
\expandafter\def\csname s2.6\endcsname{ten point six }
\expandafter\def\csname s5\endcsname{five }

%%%%%%%%%%%%%%%%%%%

\s1.4more text \s2.6 and more

\t1.4more text \t2.6 and more and \t5 yet more

\bye

-
Thanks. Adding the first two defs to my original code allows it to work. –  AbstractDissonance Aug 22 '12 at 11:56
One problem I have is sometimes I do not want a float but only an integer. The code fails. e.g., \s2 does not work. I tried to define a non '.' for s similar to what you have done but it doesn't work. –  AbstractDissonance Aug 22 '12 at 12:01
@DavidCarlisle: BTW, \count0 is not the best scratch register, because it is used for the page number ;-) –  Heiko Oberdiek Aug 22 '12 at 13:09
code updated with \t –  David Carlisle Aug 22 '12 at 13:10
@HeikoOberdiek you have to leave the odd trap for the unwary:-) Anyone brave enough to try this should be able to rename the registers... –  David Carlisle Aug 22 '12 at 13:11
show 1 more comment

In the following example macro \s just collects digits and dots and typesets them as shown in the question as bold subscripts. LaTeX's \@ifnextchar cannot be used, because it gobbles spaces when it looks for the next token.

\documentclass{article}
\usepackage{ltxcmds}[2011/04/14]

\makeatletter
\newcommand*{\s}{%
\begingroup
\let\tmp\ltx@empty
\s@aux
}
\newcommand*{\s@aux}{%
\ltx@ifnextchar@nospace{.}{%
\edef\tmp{\tmp.}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{0}{%
\edef\tmp{\tmp0}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{1}{%
\edef\tmp{\tmp1}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{2}{%
\edef\tmp{\tmp2}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{3}{%
\edef\tmp{\tmp3}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{4}{%
\edef\tmp{\tmp4}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{5}{%
\edef\tmp{\tmp5}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{6}{%
\edef\tmp{\tmp6}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{7}{%
\edef\tmp{\tmp7}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{8}{%
\edef\tmp{\tmp8}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{9}{%
\edef\tmp{\tmp9}%
\expandafter\s@aux\ltx@gobble
}{%
\expandafter\s@end\expandafter{\tmp}%
}}}}}}}}}}}%
}
\newcommand*{\s@end}[1]{%
\endgroup
\ensuremath{_\mathbf{#1}}%
}
\makeatother

\begin{document}
\s1.4Test and \s2more.
\end{document}


Update

It is easy to add the mapping layer including error messages, if \s is not followed by digits and dots or the digit/dot string is not defined.

\documentclass{article}
\usepackage{pgffor}
\usepackage{ltxcmds}[2011/04/14]

\makeatletter
\foreach \m in {1.1, 1.4, 2, 2.2}{%
\expandafter\protected@xdef\csname s\m\endcsname{$_\mathbf{\m}$}%
}

\newcommand*{\s}{%
\begingroup
\let\tmp\ltx@empty
\s@aux
}
\newcommand*{\s@aux}{%
\ltx@ifnextchar@nospace{.}{%
\edef\tmp{\tmp.}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{0}{%
\edef\tmp{\tmp0}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{1}{%
\edef\tmp{\tmp1}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{2}{%
\edef\tmp{\tmp2}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{3}{%
\edef\tmp{\tmp3}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{4}{%
\edef\tmp{\tmp4}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{5}{%
\edef\tmp{\tmp5}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{6}{%
\edef\tmp{\tmp6}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{7}{%
\edef\tmp{\tmp7}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{8}{%
\edef\tmp{\tmp8}%
\expandafter\s@aux\ltx@gobble
}{\ltx@ifnextchar@nospace{9}{%
\edef\tmp{\tmp9}%
\expandafter\s@aux\ltx@gobble
}{%
\ifx\tmp\@empty
\@latex@error{\string\s: no digits/dots found}\@ehc
\else
\@ifundefined{s\tmp}{%
\@latex@error{\string\s: Undefined \tmp'}\@ehc
}{%
\@nameuse{s\tmp}%
}%
\fi
\endgroup
}}}}}}}}}}}%
}
\makeatother

\begin{document}
\s1.4Test and \s2more.
\end{document}


In the next example, the parsed argument of \s is a string that starts with one or more digits, an optional dots and optional digits.

\documentclass{article}
\usepackage{pgffor}
\usepackage{ltxcmds}[2011/04/14]

\makeatletter
\foreach \m in {1.1, 1.4, 2, 2.2}{%
\expandafter\protected@xdef\csname s\m\endcsname{$_\mathbf{\m}$}%
}

\newcommand*{\s}{%
\begingroup
\let\s@tmp\ltx@empty
\futurelet\s@tok\s@startnum
}
\newcommand*{\s@startnum}{%
\s@digit\s@digitordot
\s@next
}
\newcommand*{\s@digit}[1]{%
\ifx0\s@tok
\else\ifx1\s@tok
\else\ifx2\s@tok
\else\ifx3\s@tok
\else\ifx4\s@tok
\else\ifx5\s@tok
\else\ifx6\s@tok
\else\ifx7\s@tok
\else\ifx8\s@tok
\else\ifx9\s@tok
\else
\let\s@next\s@end
\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
}
\edef\s@tmp{\s@tmp#2}%
\futurelet\s@tok
#1%
}
\newcommand*{\s@digitordot}{%
\let\s@next\s@end
\ifx.\s@tok
\else
\s@digit\s@digitordot
\fi
\s@next
}
\newcommand*{\s@endnum}{%
\s@digit\s@endnum
\s@next
}
\newcommand*{\s@end}{%
\ifx\s@tmp\@empty
\@latex@error{\string\s: no digits/dots found}\@ehc
\else
\@ifundefined{s\s@tmp}{%
\@latex@error{\string\s: Undefined \s@tmp'}\@ehc
}{%
\@nameuse{s\s@tmp}%
}%
\fi
\endgroup
}
\makeatother

\begin{document}
\s1.4Test and \s2more.
\end{document}

-
This definitely works for my case but seems excessively long and not very robust. In my post I can generate the commands in a loop and define there numerical part(or any part) using a simple list and with another post I can map them to output something else. e.g., \s2 could be equivalent to \ensuremath{_\mathbf{\map{#1}}} where \map takes 2, in this case, and turns it into whatever I want. David seems to have figure out a good method that works with my original foreach and allows the mapping. –  AbstractDissonance Aug 22 '12 at 13:52
\def\s#1.#2{$_\mathbf{#1.#2}$}