Test whether last letter of a string is upper case or not

This defines a conditional that tests if the last item in a token list is uppercase; the token list should consist only of ASCII characters.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\prg_new_protected_conditional:Npnn \ae_if_last_uc:n #1 { T , F , TF }
 {
  \tl_set:Nx \l_ae_testa_tl { \tl_item:nn { #1 } { -1 } }
  \tl_set:Nx \l_ae_testb_tl { \text_uppercase:V \l_ae_testa_tl }
  \tl_if_eq:NNTF \l_ae_testa_tl \l_ae_testb_tl
   { \prg_return_true: }
   { \prg_return_false: }
 }
\cs_generate_variant:Nn \text_uppercase:n { V }

% A test
\ae_if_last_uc:nTF { abc } { \typeout{UC} } { \typeout{LC} }
\ae_if_last_uc:nTF { abC } { \typeout{UC} } { \typeout{LC} }

\ExplSyntaxOff

\stop

The test outputs

LC
UC

Your problem is common: \tl_to_uppercase:n (that is, the primitive \uppercase) is not expandable.


Let's look at your macros.

\NewDocumentCommand{\aeupcasefirstelement}{ m }
 {
  \tl_set:Nn \l_ae_lasttoken_tl        { \tl_head:n { #1 } }
  \tl_set:Nn \l_ae_upper_lasttoken_tl  { \tl_to_uppercase:n {  \l_ae_lasttoken_tl } }
  %% show results of these actions
  \textbf{ \l_ae_lasttoken_tl {~   vs.  ~} \l_ae_upper_lasttoken_tl }
 }

With \aeupcasefirstelement{abc} you store in \l_ae_lasttoken_tl the tokens \tl_head:n{a} and in \l_ae_upper_lasttoken_tl the tokens

\tl_to_uppercase:n{\l_ae_lasttoken_tl}

which is surely not what you want. The fact that the printed result seems to be correct is purely incidental, because during typesetting TeX expands and executes tokens. In order to store the first item in \l_ae_lasttoken_tl you need to expand the function \tl_item:nn, so use

\tl_set:Nx \l_ae_lasttoken_tl { \tl_item:nn { #1 } }

would be the correct idiom. For uppercasing, you have to resort to \text_uppercase:n as I did above, or do the uppercasing in a different and indirect fashion:

\exp_args:Nx \tl_to_uppercase:n
 {
  \exp_not:n { \tl_set:Nn \l_ae_lasttoken_uppercase_tl } { \l_ae_lasttoken_tl }
 }

(defining a variant \tl_to_uppercase:x would be better, of course).

The biggest problem is that \tl_to_uppercase:n is not expandable and does its work in a curious way. Also note that \tl_to_uppercase:n no longer exists in expl3, as its oddity and the way it works are not in par with the scope of expl3 code.


This grabs the last char and stuffs it in \lastchar. Then it uppercases that char and stuffs it in \uplastchar. Then, a simple \if will differentiate.

\documentclass{article}
\usepackage{stringstrings}
\begin{document}
\def\strng{This is a test of the emergency broadcast system}
\strng

\substring[q]{\strng}{$}{$}
\edef\lastchar{\thestring}

\caseupper[q]{\thestring}
\edef\uplastchar{\thestring}

\lastchar~\uplastchar

\if\lastchar\uplastchar SAME\else DIFFERENT\fi

\end{document}

p.s. In general, the strings cannot contain macros, though there are various exceptions and some workarounds, if necessary.

Tags:

Expl3

Xparse