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.

I'm writing a textboox in latex, and I have things like

\textit{some definition}\index{Some Definition}

all over the place. I'd like to combine them into something like

\define{some definition}

and have it expand automagically. So I can have

\newcommand{\define}[2]{\textit{#1}\index{#2}}

which works, but forces me to include both arguments. The second argument is almost always the first argument with the first letter of each word uppercased. How can I write a command which uppercases the first character of each word?

Suggestions of better indexing best practices would also be appreciated.

share|improve this question

4 Answers 4

up vote 15 down vote accepted
\documentclass{article}
\usepackage{makeidx}\makeindex
\newcommand*{\formatfirst}[1]{\MakeUppercase{#1}}
\makeatletter
\newcommand*{\mymacro}[1]{%
  \expandafter\formatfirst\expandafter{\@car #1\@empty\@nil}%
  \@cdr #1\@empty\@nil}
\newcommand*\myMakeUpperCase[1]{%
  \def\@myuppercasewords{\myuppercase@i#1 \@nil}%
    {\itshape\@myuppercasewords}\index{#1@\@myuppercasewords}}
\def\myuppercase@i#1 #2\@nil{%
  \mymacro{#1}%
  \ifx\\#2\\%
  \else
    \@ReturnAfterFi{%
      \space
      \myuppercase@i#2\@nil
    }%
  \fi} 
\long\def\@ReturnAfterFi#1\fi{\fi#1} 
\makeatother

\begin{document}
foo
\myMakeUpperCase{capital letter} bar
\myMakeUpperCase{Next one} baz
\myMakeUpperCase{two words}

\printindex

\end{document} 

alt text

share|improve this answer
    
Close, but if I do it this way then the index isn't sorted, because all entries start with \MakeUpperCase. Is there any way to force that macro to expand before building the index? –  Nate Dec 31 '10 at 0:12
1  
@Nate: ah, I see. change the line to ` {\itshape\@myuppercasewords}\index{#1@\@myuppercasewords}}`. I edited also the code above and the output picture. –  Herbert Dec 31 '10 at 6:50
    
Thanks! Out of curiosity, why does everybody leave percent signs where they open and close brackets? It just begins a comment, right? –  Nate Dec 31 '10 at 15:53
2  
Also, just realized that if you have two entries for "alpha" and "Alpha" then the index will display them both as "Alpha" but won't combine them into the same entry like it should. Again, I don't suppose there's any way to make the uppercase macro expand earlier? I can just write a pre-processing script that uppercases the character in the ind file, but it would be nice to have it done in tex. –  Nate Dec 31 '10 at 16:02
3  
@Nate: The percent signs begin a comment, which swallows white space. If you didn't use them, then, for some mis-defined command \foo, if you wrote \foo., it would typeset incorrectly as foo . –  Antal S-Z Dec 31 '10 at 19:23

The mfirstuc package from the glossaries bundle provides the handy \capitalisewords command which could be used here. I adapted Herbert's example and the output is the same:

\documentclass{article}

\usepackage{mfirstuc}
\usepackage{makeidx}\makeindex

\makeatletter
\newcommand*\define[1]{%
  \textit{#1}%
  \index{#1@\protect\capitalisewords{#1}}%
   }
\makeatother

\begin{document}
foo
\define{capital letter} bar
\define{Next one} baz
\define{two words}

\printindex

\end{document}
share|improve this answer

I am not sure if I understand your question correctly, but a short macro as shown below, will capitalize the first word you type and place it in the index.

\documentclass[11pt]{article} 
\usepackage{index}
\makeindex
\begin{document}
\def\Index#1{\def\x##1##2{\MakeUppercase{##1}{##2}}\textit{\x#1} \index{\x#1}} 
\Index{alpha}

\def\indeX#1#2{\def\x##1##2{\MakeUppercase{##1}{##2}}\x#1 \index{\x#2}} 
\Index{alpha}

\indeX{test}{this}

\printindex
\end{document}
share|improve this answer
    
Yes, but how would I make this work with \Index{alpha beta}? –  Nate Dec 30 '10 at 18:15
    
@Nate what is it exactly you want to print and what do you want to place in the Index? –  Yiannis Lazarides Dec 30 '10 at 18:52
    
@Nate see edit. –  Yiannis Lazarides Dec 30 '10 at 19:07
    
I modified this to keep the index sorted: \def\index#1{\def\x##1##2{\MakeUppercase{##1}{##2}}#1\inindex{#1@\x#1}} –  fuenfundachtzig Nov 21 '11 at 9:01

My pure LaTex3 solution:

\documentclass{minimal}
\usepackage{xparse}
\usepackage[T1]{fontenc}

\ExplSyntaxOn

\NewDocumentCommand{\ucFirst}{m} {
  \sphakka_ucfirst:f {#1}
}
\cs_new_protected:Npn \sphakka_ucfirst:f #1 {
  \exp_last_unbraced:Nx \tl_to_uppercase:n {\tl_head:f {#1}}
  % notice the ~ to put back blank padding
  \tl_tail:f {#1}~
}

\NewDocumentCommand{\ucFirstMore}{m} {
  \sphakka_ucfirstmore:f {#1}
}
\cs_new_protected:Npn \sphakka_ucfirstmore:n #1 {
  % must convert the TL into a SEQ
  \seq_set_split:Nnn \l_sphakka_seq {~} {#1}
  \seq_map_function:NN \l_sphakka_seq \sphakka_ucfirst:f
}
\cs_generate_variant:Nn \sphakka_ucfirstmore:n {f}

\ExplSyntaxOff

\begin{document}

\def\word{bar}
\def\sentence{foo bar baz}

[Plain word] quux => \ucFirst{quux}\par
[Word via macro]~\word~=> \ucFirst{\word}\par
[Plain sentence] foo bar baz => \ucFirstMore{foo bar baz}\par
[Sentence via macro]~\sentence~=> \ucFirstMore \sentence \par

\end{document}

Though simple, the above solution leaves a trailing non-breakable space which is rather tricky to get rid of. Thus, I wrote a variant that stores capitalized tokens into another seq, then glues them by spaces:

\documentclass{minimal}
\usepackage{xparse}
\usepackage[T1]{fontenc}

\ExplSyntaxOn

\NewDocumentCommand \ucFirst {>{\TrimSpaces}m} {
  % Won't trim explicit trailing `\space's... why?
  \sphakka_ucfirst:f {#1}
}
\cs_new_protected:Npn \sphakka_ucfirst:f #1 {
  \exp_last_unbraced:Nf \tl_to_uppercase:n {\tl_head:f {#1}}
  \tl_tail:f {#1}
}

\NewDocumentCommand \ucFirstMore {>{\TrimSpaces}m} {
  \sphakka_ucfirstmore:f {#1}
}
\seq_new:N \l_out_seq
\cs_new_protected:Npn \sphakka_ucfirstmore:n #1 {
  % split by blanks. Can anybody tell me why `\space` doesn't work?
  \seq_set_split:Nnn \l_in_seq {~} {#1}
  % remove empty/blank items
  \seq_remove_all:Nn \l_in_seq {}
  \seq_remove_all:Nn \l_in_seq {\space}
  % capitalize each token and store it into another seq
  \seq_map_inline:Nn \l_in_seq {
    \seq_put_right:Nn \l_out_seq {\sphakka_ucfirst:f {##1}}
  }
  \seq_use:Nnnn \l_out_seq {\space}{\space}{\space}
  \seq_clear:N \l_out_seq
}
\cs_generate_variant:Nn \sphakka_ucfirstmore:n {f}


\ExplSyntaxOff

\begin{document}

\edef\word{\space  quux\space }
\edef\sentence{  \space  foo  bar baz \space }

\begin{tabular}[c]{p{.6\linewidth}l}
  \verb|\word|                                          & \verb|`\space  quux\space '|\\
  \verb|\sentence|                                      & \verb|`\space  foo  bar baz \space '|\\
  \\
  \verb|\ucFirst{\space  quux\space }|                  & `\ucFirst{\space  quux\space }'\\
  \verb|\ucFirst{\word}|                                & `\ucFirst{\word}' \\
  \verb|\ucFirstMore{\word}|                            & `\ucFirstMore{\word}' \\
  \verb|\ucFirstMore{  \space  foo  bar baz \space }|   & `\ucFirstMore{  \space  foo  bar baz \space }'\\
  \verb|\ucFirstMore{\sentence}|                        & `\ucFirstMore{\sentence}'\\
\end{tabular}

\end{document}

lualatex output

There are just a couple of minor glitches that I couldn't resolve (possibly because of my inexperience...):

  • Why \TrimSpaces (or \tl_trim_spaces) doesn't remove explicit trailing \spaces?

  • Why \seq_set_split cant't split by \space?

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.