# How to capitalize letter (using \uppercase) that has been assigned to \let (or to \def)?

I don't seem to be able to capitalize a letter that has been assigned to \let.

\let\zTest=t
\uppercase{\zTest} % still small


ADDENDUM: I've tried \def\zTest{t} just now and it didn't work either (but \uppercase{t} works).

• With a recent version of LaTeX you could do \expandafter\uppercase\expandafter{\expanded{<stuff>}}, that would work with <stuff> being letters and macros defined using \newcommand or \def, but not for \let. – Skillmon Nov 17 at 16:27
• \uppercase and \lowercase only act on explicit character tokens. Implicit character tokens and macros expanding to character tokens are not touched. An character token produced with \let doesn't have a \uccode (or \lccode) for \uppercase to do its thing. Try \showthe\uccodet and then \showthe\uccode\zTest (the latter raises an error). – Phelype Oleinik Nov 17 at 16:29
• @bp2017 Did you see the 'tl action' approach I linked to in an earlier question: you can pick up spaces in advance, and process them without \let, if you are prepared to normalise the charcode of {/}. – Joseph Wright Nov 17 at 17:02
• \uppsercase does no expansion: when you use \def, the macro token is not affected as it's not a char – Joseph Wright Nov 17 at 17:09
• @bp2017 "prevent spaces from being gobbled" -- You can have TeX "look" whether there are some spaces. In this context the routines \UD@CheckWhetherNull, \UD@CheckWhetherBrace, \UD@CheckWhetherLeadingSpace in my answer to the question "How do I pad a string argument to a macro to a set length string" might be of interest. ;-) – Ulrich Diez Nov 17 at 17:21

\uppercase and \lowercase

• do only apply to explicit character tokens.
• do not trigger expansion after finding
• either the left brace { of the ⟨balanced text⟩ that is to be uppercased/lowercased.
• or the single not-brace-nested unexpandable non-⟨filler⟩-token that is to be uppercased/lowercased. (⟨filler⟩ denotes a sequence of \relax and/or explicit/implicit spaces.)

When using \csname..\endcsname instead of using the control-word-token directly, you can probably do somehing like this:

\let\zTest=t
\let\ZTEST=T
\let\ztest=t
\def\Ztest{t}

% \zTest and \ZTEST and \ztest are implicit character tokens.
% Lets use uppercased/lowercased \csname..\endcsname for selecting
% which implicit character token to use:

\csname zTest\endcsname

\uppercase{\csname zTest\endcsname}%

\lowercase{\csname zTest\endcsname}%

% \Ztest is a macro, expanding to explicit character token "t".
% You can use \expandafter for triggering "toplevel-expansion"
% while \uppercase/\lowercase still searches the "{" that
% marks the begin of the balanced text:

\Ztest

\uppercase\expandafter{\Ztest}%

\lowercase\expandafter{\Ztest}%

% With more recent TeX-engines, where \expanded is available,
% you can do:
%   \lowercase\expandafter{\expanded{\Ztest}}%
% "toplevel-expansion" of \expanded<general text> will deliver
% "total expansion" of the content of the <general text>'s
% <balanced text>

\bye


The following is a macro that is able to uppercase a let token if it was let to a letter (e.g., with \let\foo=t assuming standard category codes). It does so by first checking whether the magic tokens the letter are the start of the meaning of the passed in token, and then grabs the letter following it and uppercases that, if the meaning doesn't seem to be a letter then the input is output. The test is only applied to the first token of the input, but it is not checked whether the input is only a single token (so \uppercaselettoken{t more stuff} would see that t is a letter but passes more stuff to \uppercase, too. So this is only a proof-of-concept not a stable implementation.

\documentclass[]{article}

\let\foo=t

\makeatletter
\def\uppercaselettoken@ifletter#1%
{%
\def\uppercaselettoken@ifletter##1#1##2\end
{%
\if\relax\detokenize{##2}\relax
\expandafter\@secondoftwo
\else
\if\relax\detokenize{##1}\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\expandafter\@firstoftwo}
{\expandafter\@secondoftwo}%
\fi
}%
\def\uppercaselettoken@letter#1##1\end{\uppercase{##1}}%
}
\expandafter\uppercaselettoken@ifletter\expandafter{\detokenize{the letter }}
\long\edef\uppercaselettoken@#1#2%
{%
\noexpand\uppercaselettoken@ifletter#1\detokenize{the letter }\noexpand\end
{%
\noexpand\uppercaselettoken@letter#1\noexpand\end
}%
{#2}% not a letter, no uppercasing
}

\newcommand\uppercaselettoken[1]
{%
\expandafter\uppercaselettoken@\expandafter{\meaning#1}{#1}%
}
\makeatother

\usepackage{unravel}

\begin{document}
\uppercaselettoken{\foo}
\uppercaselettoken{t}% works too
\end{document}

• Might add this to \tl_upper_case:n – Joseph Wright Nov 17 at 17:08
• @bp2017 well, we have to teach TeX something which was originally not meant to be done, so yes, this tends to be complicated. – Skillmon Nov 17 at 17:12
• @JosephWright not sure whether it should be part of \tl_upper_case:n, but one could define a variant (something like \tl_upper_case_e:n) which does this. It's your choice :) – Skillmon Nov 17 at 17:13
• I sometimes use implicit characters and/or \char in situations where uppercasing/lowercasing of initials and shortcuts of names and the like is to be prevented.. ;-> – Ulrich Diez Nov 17 at 17:45

While it is possible to implement something that interrogates the meaning of unexpandable tokens, recognises implicit characters defined by \let and look up their upper case form, there are very few reasons to get into that situation, using \def (or \renewcommand) is the documented LaTeX interface and is essentially trivial to make work as you just have to expand the macros before uppercasing, and it works out of the box using LaTeX:

\documentclass{article}

\begin{document}

\let\zza=a
\let\zzb=b
\let\zzc=c

1 \MakeUppercase{\zza\zzb\zzc}

\renewcommand\zza{a}
\renewcommand\zzb{b}
\renewcommand\zzc{c}

2 \MakeUppercase{\zza\zzb\zzc}

\end{document}
`