Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Two things I understand and one thing I don't:

I often use \csname to create user-defined tokens. For instance, the following code uses \expandafter to expand everything between \csname and \endcsname before \gdefing the result:

\newcommand{\mycommand}[1]{%
  \expandafter\gdef\csname #1\endcsname{Here is #1 printed.}%
}

\begin{document}
\mycommand{abc} % Creates a macro \abc
Demonstration: \abc % Prints Demonstration: Here is abc printed.
\end{document}

I wanted to do something similar by using \mycommand{abc} to create a macro \Abc (note the capital letter). Unfortunately, \uppercase cannot be used inside \csname. (I'm guessing some parts expand to TeX primitives?) But I found a somewhat related answer from Heiko Oberdiek (http://newsgroups.derkeiler.com/Archive/Comp/comp.text.tex/2006-02/msg01220.html) and created the following, which I don't entirely understand.

It should create a new uppercase token, and I think it is working, since I can then \let it to another macro and it does not error.

\newcommand{\mycommand}[1]{% 
  \uppercase\expandafter{\expandafter\csname #1}\endcsname% Creates token 
}%
\def\temp{if it worked}
\let\Abc\temp% Now \Abc expands to something other than \relax

\begin{document}
\mycommand{abc}% Creates \Abc
This lets you see \Abc.% Prints This lets you see if it worked.
\end{document}

So my question is: how can I create an uppercase token and define the expansion at the same time? (Basically, I want to combine both of the above approaches.) Here are two ways I have tried (both return Error: extra \endcsname).

\newcommand{\mycommand}[1]{% 
  \expandafter\gdef%   I think this tries to do \gdef\uppercase = bad 
  \uppercase\expandafter{\expandafter\csname #1}\endcsname{the macro #1 expanded}%  
}%
\mycommand{abc}
Use \Abc. % Should print Use the macro abc expanded.

or

\newcommand{\mycommand}[1]{% 
  \expandafter\gdef\expandafter{% 
  \uppercase\expandafter{\expandafter\csname #1}\endcsname}{the macro #1 expanded}% 
}%
\mycommand{abc}
Use \Abc. % Should print Use the macro abc expanded.
share|improve this question

4 Answers 4

up vote 15 down vote accepted

You have to isolate the first token in #1 from the rest and uppercase it; the fact that \uppercase doesn't expand anything and puts back the token list into the input stream after its operation can be exploited in the following way:

\newcommand{\mycommand}[1]{\mycommandaux#1\relax}
\def\mycommandaux#1#2\relax{%
  \uppercase{\expandafter\gdef\csname #1}#2\endcsname{the macro #1#2 expanded}%
}
\mycommand{abc}
\show\Abc

Of course an empty argument to \mycommand will result in an error.

If you want to provide a definition, say

\mycommand{abc}{Something else}

to be equivalent to \def\Abc{Something else}, just leave out the tokens after \endcsname

\newcommand{\mycommand}[1]{\mycommandaux#1\relax}
\def\mycommandaux#1#2\relax{%
  \uppercase{\expandafter\gdef\csname #1}#2\endcsname
}
\mycommand{abc}{Something else}
\show\Abc

The command \uppercase is a bit stranger than other TeX primitives. Indeed the <general text> it requires as argument first does a travel down TeX's stomach to be "regurgitated" after each character token has been transformed using the \uccode vector: if a character has positive \uccode, TeX will transform it into that character (the category code is unchanged). So, for instance, TeX is setup so that \uccode`a=`A and so an a becomes an A after regurgitation. Non character token are left unchanged and no expansion is performed.

Here's the working in slow motion (first version).

  1. \mycommand{abc}
    Here #1 is abc

  2. \mycommandaux abc\relax
    Here #1 is a and #2 is bc (argument #2 is delimited by \relax, while #1 is undelimited, so the only first token is grabbed)

  3. \uppercase{\expandafter\gdef\csname a}bc\endcsname {the macro abc expanded}
    Tex executes the \uppercase and puts back

    \expandafter\gdef\csname A
    

    in the input stream.

  4. \expandafter\gdef\csname Abc\endcsname{the macro abc expanded}

  5. \gdef\Abc{the macro abc expanded}

Et voilà.

share|improve this answer
    
Thank you. I adapted this to the (more complicated) problem at home and it works beautifully. Voting as answer simply because it has syntax close to what I was using before, so I can follow it. Clearly \uppercase has behavior far different than what I expected. –  Natalie May 27 '12 at 23:16
    
That was my first idea, too, but somehow I turned it more complicated while implementing it ;-) You shouldn't code TeX while correcting your PhD thesis ;-) –  Martin Scharrer May 27 '12 at 23:38

The problem is that \uppercase is not expandable. You can't use it with \expandafter. I would expand the argument first, as good measure, then read the first letter using a second, internal macro, then use \uppercase to change that letter. Finally a second internal macro reads the new uppercase letter and the rest of the name and makes the definition. The original name can also be passed as a third argument if required:

\makeatletter
\newcommand{\mycommand}[1]{% 
    \begingroup
    \edef\@tempa{#1}%
    \expandafter\endgroup\expandafter\@mycommand\@tempa\@nnil{#1}%
}
\def\@mycommand#1{%
    \uppercase{\@@mycommand{#1}}%
}
\def\@@mycommand#1#2\@nnil#3{%
    \global\@namedef{#1#2}{the macro #3 expanded}%%
}
\makeatother
\mycommand{abc}
\show\Abc
share|improve this answer
    
Wow, this is entirely too clever for me! So in pseudo-code: the first part ends up executing \@mycommand abc\@nnil{abc} before the group closes. The second part uses \@mycommand to bite off the a and results in: \uppercase{\@@mycommand{a}}bc\@nnil{abc} How is it that \@@mycommand does not mind the double }}? I don't understand what happens next. Does \uppercase do its thing, or does \@@mycommand? –  Natalie May 27 '12 at 22:55
    
@Natalie: \uppercase is executed first, takes \@@mycommand{a} (because it's in {..} after it) and turns all tokens to their uppercase version. Macro are unchanged, afterwards it places the whole thing back, i.e. \@@mycommand{A} is placed before bc\@nnil{abc}, then \@@mycommand reads the {A} as first argument and everything to the next \@nnil as second. The {abc} afterwards is taken as third argument. –  Martin Scharrer May 27 '12 at 23:36
    
Very neat! Thanks for the explanation. Using the fact that \uppercase doesn't expand or change macros is a good trick. –  Natalie May 28 '12 at 1:49

This is a good example of why LuaTeX is useful.

\def\defineuppercase#1%
    {\ctxcommand{defineuppercase("#1")}}

\startluacode
  function commands.defineuppercase(s)
      local upper = string.gsub(s, "^%l", string.upper)
      context.setgvalue(upper)
  end
\stopluacode

\defineuppercase{one}{Something}

\show\One
\end

I am using ConTeXt MkIV, but the code can be easily translated to LaTeX as well.

share|improve this answer

You can also do this with the xstring package. So after defining \mycommand{abc}, and \mycommand{dbc}, you can use \Abc, and \Def to get:

enter image description here

Note:

  • The code below is not complete in that it only converts the letters a,...,f to A,...,F, but extending it should not be too difficult.

Code:

\documentclass{article}
\usepackage{xstring}

\newcommand{\mycommand}[1]{%
    \IfBeginWith{#1}{a}{\StrSubstitute{#1}{a}{A}[\newMacroName]}{}%
    \IfBeginWith{#1}{b}{\StrSubstitute{#1}{b}{B}[\newMacroName]}{}%
    \IfBeginWith{#1}{c}{\StrSubstitute{#1}{c}{C}[\newMacroName]}{}%
    \IfBeginWith{#1}{d}{\StrSubstitute{#1}{d}{D}[\newMacroName]}{}%
    \IfBeginWith{#1}{e}{\StrSubstitute{#1}{e}{E}[\newMacroName]}{}%
    \IfBeginWith{#1}{f}{\StrSubstitute{#1}{f}{F}[\newMacroName]}{}%
    % ... complete this ...
    \expandafter\gdef\csname \newMacroName\endcsname{Here is #1 printed.}%
}%

\begin{document}
\mycommand{abc} % Creates a macro \Abc
Demonstration: \Abc % Prints Demonstration: Here is abc printed.


\mycommand{dbc} % Creates a macro \Dbc
Demonstration: \Dbc % Prints Demonstration: Here is abc printed.
\end{document}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.