4

This might be a very basic problem (as a follow-up to this question) but I cannot figure out how to do it: I need a macro \mycmd{sometext} that yields a string depending on the first character of its one argument. This resulting string should afterwards be capitalized by \makefirstuc.

\documentclass{article}
\usepackage{xparse}  % used in example below
\usepackage{pgffor}  % used in example below
\usepackage{xstring} % used in example below

\newcommand{\mycmd}[1]{
  % here, I define a list of letters {a,e,i,o,u,A,E,I,O,U}
  % that will lead to the output "an " in case
  % the argument string starts by one of them.
  % Otherwise the output shall be "a ".
}

\begin{document}
  \mycmd{somestring}                % should print "a "
  \makefirstuc{\mycmd{sometext}}    % should print "A "
  \mycmd{otherstring}               % should print "an "
  \makefirstuc{\mycmd{otherstring}} % should print "An "
\end{document}

I tried realizing this using the pfgfor package for the loop and therein comparing the first character with \IfBeginWith from the xstring package. However, this apparently leads to unexpandable commands so that \makefirstuc fails. How can one achieve an expandable command with this functionality?

So far I created the following unexpandable command:

\NewDocumentCommand{\mycmd}{m}{%
  \def\undefart{a\space}%
  \foreach \c in {a,e,i,o,u,A,E,I,O,U}{%
    \IfBeginWith{#1}{\c}{\global\def\undefart{an\space}}{}%
  }%
  \undefart%
}
0

4 Answers 4

5

This is easy enough using expl3 (there are several possible approaches):

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\DeclareExpandableDocumentCommand \mycmd { m }
  {
    \__mycmd_loop:nN {#1} aeiouAEIOU \q_recursion_tail \q_recursion_stop
  }
\cs_new:Npn \__mycmd_loop:nN #1#2
  {
    \quark_if_recursion_tail_stop_do:nn {#2} { a }
    \tl_if_head_eq_charcode:nNT {#1} #2
      {
        \use_i_delimit_by_q_recursion_stop:nw { an }
      }
    \__mycmd_loop:nN {#1}
  }
\ExplSyntaxOff
\usepackage{mfirstuc}
\begin{document}

  \mycmd{somestring}                % should print "a "
  \emakefirstuc{\mycmd{sometext}}    % should print "A "
  \mycmd{otherstring}               % should print "an "
  \emakefirstuc{\mycmd{otherstring}} % should print "An "
\end{document}

As \makefirstuc does no expansion, I've had to use the e version. I'd probably prefer to get around that by using the expandable (and Unicode-aware) \text_titlecase:n:

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\DeclareExpandableDocumentCommand \mycmd { m }
  {
    \__mycmd_loop:nN {#1} aeiouAEIOU \q_recursion_tail \q_recursion_stop
  }
\cs_new:Npn \__mycmd_loop:nN #1#2
  {
    \quark_if_recursion_tail_stop_do:nn {#2} { a }
    \tl_if_head_eq_charcode:nNT {#1} #2
      {
        \use_i_delimit_by_q_recursion_stop:nw { an }
      }
    \__mycmd_loop:nN {#1}
  }
\cs_new_eq:NN \Mymakefirstuc \text_uppercase:n
\ExplSyntaxOff
\begin{document}

  \mycmd{somestring}                % should print "a "
  \Mymakefirstuc{\mycmd{sometext}}    % should print "A "
  \mycmd{otherstring}               % should print "an "
  \Mymakefirstuc{\mycmd{otherstring}} % should print "An "
\end{document}

Depending on the number of cases, it might be desirable to lowercase all of the input first

\DeclareExpandableDocumentCommand \mycmd { m }
  {
    \exp_args:Nf \__mycmd:n { \text_lowercase:n {#1} }
  }
\cs_new:Npn \__mycmd:n #1
  {
    \__mycmd_loop:nN {#1} aeiou \q_recursion_tail \q_recursion_stop
  }
1
  • One might use \str_case:nnF or \int_case:nnF here, and could use force the case of the input (to avoid needing two comparisons) using e.g. \tl_lower_case:f.
    – Joseph Wright
    Feb 8, 2016 at 15:37
5

Here's an approach with expl3

\documentclass{article}
\usepackage{xparse,glossaries}

\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\indef}{m}
 {
  \str_case_x:nnF { \tl_head:f { \tl_lower_case:n { #1 } } }
   {
    {a}{an}
    {e}{an}
    {i}{an}
    {o}{an}
    {u}{an}
  }
  {a}~#1
 }
\ExplSyntaxOff

\begin{document}

\indef{abc} --- \indef{cde} --- \indef{ABC} --- \indef{CDE}

\emakefirstuc{\indef{abc}} --- \emakefirstuc{\indef{cde}} ---
\emakefirstuc{\indef{ABC}} --- \emakefirstuc{\indef{CDE}}

\end{document}

enter image description here

2
  • Indeed, this was another approach I was thinking about :-)
    – Joseph Wright
    Feb 8, 2016 at 16:04
  • @JosephWright Maybe less efficient, but easier to read.
    – egreg
    Feb 8, 2016 at 16:12
2

Here's a LuaLaTeX-based solution. It defines two fully-expandable "wrapper" macros named \mycmd and \mkfirstuc, which pass their arguments to Lua functions named mycmd and mkfirstuc. The Lua functions perform the actual work of prefixing "an " or "a " to a string and of upper-casing the first character in the string, respectively.

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}

%% Lua-side code
\usepackage{luacode}
\begin{luacode}
function mycmd ( s )
  if string.match ( string.sub(s,1,1) , "[aeiouAEIOU]" ) then
    return tex.sprint ("an " .. s)
  else
    return tex.sprint ("a " .. s)
  end
end
function mkfirstuc ( s )
  return tex.sprint ( string.upper(string.sub(s,1,1)) .. string.sub(s,2) )
end
\end{luacode}

%% TeX-side code
\newcommand\mycmd[1]{\directlua{mycmd(\luastring{#1})}}
\newcommand\mkfirstuc[1]{\directlua{mkfirstuc(\luastring{#1})}}

\begin{document}
\mycmd{abc}, \mycmd{def}, \mycmd{ABC}, \mycmd{DEF}.

\mkfirstuc{\mycmd{abc}}, \mkfirstuc{\mycmd{def}}, 
\mkfirstuc{\mycmd{ABC}}, \mkfirstuc{\mycmd{DEF}}. 
\end{document}
1

Is this what is meant? It is not the most effective usage of expl3, I know ;-)

\documentclass{article}
\usepackage{xparse}  % used in example below
\usepackage{pgffor}  % used in example below
\usepackage{xstring} % used in example below

\ExplSyntaxOn

\clist_set:Nn \l_tinytot_lowercaseletters_clist {a,e,i,o,u}
\clist_set:Nn \l_tinytot_letters_clist {a,e,i,o,u,A,E,I,O,U}

\NewDocumentCommand{\makefirstuc}{m}{%
  \tl_to_uppercase:n {#1}
}

\NewDocumentCommand{\checkstart}{m}{%
  \tl_set:Nx \l_tmpa_tl {#1}
  \tl_trim_spaces:N \l_tmpa_tl
  \tl_set:Nx \l_tmpb_tl { \tl_item:Nn \l_tmpa_tl {1}}
  \clist_if_in:NVTF \l_tinytot_letters_clist {\l_tmpb_tl }{%
    \clist_if_in:NVTF \l_tinytot_lowercaseletters_clist {\l_tmpb_tl}
    {
      an
    }{
      An
    }
  }{
    \clist_if_in:NVTF \l_tinytot_lowercaseletters_clist {\l_tmpb_tl}
    {
      a
    }{
      A
    }
  }
}  
\ExplSyntaxOff

\newcommand{\mycmd}[1]{%
  \checkstart{#1}
  % here, I define a list of letters {a,e,i,o,u,A,E,I,O,U}
  % that will lead to the output "an " in case
  % the argument string starts by one of them.
  % Otherwise the output shall be "a ".
}

\begin{document}
\mycmd{somestring}                % should print "a "
\makefirstuc{\mycmd{sometext}}    % should print "A "
\mycmd{otherstring}               % should print "an "
\makefirstuc{\mycmd{otherstring}} % should print "An "
\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .