27

Is there a way to define a command that changes the colour of any capital letter in an input string?

Most of the results I find when I type "LaTeX string capital" are results about capitalizing the first letter of each word. Here I would like to process all the capital letters of a string.

I know TeX is really nice for many reasons, but when it comes to actual programming I really feel like there is nothing else like it. I hope I won't offend anyone if I say that despite how grateful I am for LaTeX to even exist, I sometimes wish TeX's syntax was more traditional when it comes to actual programming.

3
  • 3
    For xelatex, see tex.stackexchange.com/questions/33855/… Apr 24, 2014 at 11:10
  • 1
    For a LuaLaTeX approach, have a look at the chickenize package. May 1, 2014 at 19:11
  • Not sure if anyone read this, but there certainly are efforts to make (La)TeX programming more accessible. There are expl3, functional package, Lua, embedding Python in TeX etc. (and some of my unpublished packages.)
    – user202729
    Jul 2, 2022 at 15:45

4 Answers 4

25

You can do it with a regular expression, if you have the input string as an argument.

\documentclass{article}
\usepackage{xparse}
%\usepackage{l3regex} % only with expl3 before June 2017
\usepackage{xcolor}


\ExplSyntaxOn
\NewDocumentCommand{\colorcap}{ O{blue} m }
 {
  \sheljohn_colorcap:nn { #1 } { #2 }
 }

\tl_new:N \l__sheljohn_colorcap_input_tl
\cs_new_protected:Npn \sheljohn_colorcap:nn #1 #2
 {
  % store the string in a variable for usage with \regex_replace_all:nnN
  \tl_set:Nn \l__sheljohn_colorcap_input_tl { #2 }
  \regex_replace_all:nnN
   { ([A-Z]+) } % search a capital letter (or more)
   { \c{textcolor}\cB\{#1\cE\}\cB\{\1\cE\} } % replace the match with \textcolor{#1}{<match>}
   \l__sheljohn_colorcap_input_tl
  \tl_use:N \l__sheljohn_colorcap_input_tl
 }
\ExplSyntaxOff

\begin{document}
\colorcap{Once Upon a Time}

\colorcap[red]{Once Upon a Time}
\end{document}

enter image description here

Note

The syntax for the replacement string is a bit convoluted, but not difficult:

  • \c{textcolor} means “the control sequence \textcolor
  • \cB\{ means “an opening brace with its normal function of B⁣egin group
  • \cE\} means “a closing brace with its normal function of E⁣nd group

Thus the replacement text can be read as

\textcolor{#1}{<match>}

where #1 is the optional argument to \colorcap.

A version that also supports accents, provided they're input in the “classical” way with a macro.

\documentclass{article}
\usepackage{xparse}
\usepackage{xcolor}

\ExplSyntaxOn
\NewDocumentCommand{\colorcap}{ O{blue} m }
 {
  \sheljohn_colorcap:nn { #1 } { #2 }
 }

\tl_new:N \l__sheljohn_colorcap_input_tl
\cs_new_protected:Npn \sheljohn_colorcap:nn #1 #2
 {
  % store the string in a variable
  \tl_set:Nn \l__sheljohn_colorcap_input_tl { #2 }
  \regex_replace_all:nnN
    % search a capital letter (or more)
    { ([A-Z]+|\cC.\{?[A-Z]+\}?) }
    % replace the match with \textcolor{#1}{<match>}
    { \c{textcolor}\cB\{#1\cE\}\cB\{\1\cE\} }
    \l__sheljohn_colorcap_input_tl
  \tl_use:N \l__sheljohn_colorcap_input_tl
 }
\ExplSyntaxOff

\begin{document}
\colorcap{\`Once \r{U}pon a Time}

\colorcap[red]{Once Upon a Time}
\end{document}

enter image description here

Here \cC. matches any control sequence, \{? zero or one open brace, \}? zero or one closed brace, so both \`O and \r{U} inputs are caught.

5
  • That looks more like the correct answer actually :) But is it for LaTeX3 only? Or is l3regex available on texlive/popular LaTeX2e distributions?
    – Jonathan H
    Apr 24, 2014 at 14:38
  • Could you elaborate on the functions of each line in your code a little bit more?
    – azetina
    Apr 24, 2014 at 15:16
  • 1
    @Sh3ljohn The expl3 suite is available on every updated TeX distribution.
    – egreg
    Apr 24, 2014 at 16:26
  • 1
    @azetina Done; I had only a few minutes before the LaTeX class when I wrote the answer. ;-)
    – egreg
    Apr 24, 2014 at 16:38
  • 3
    Great! I envy your students for having such a wonderful LaTeX teacher like you. They will surely be guided on the right path :-)
    – azetina
    Apr 24, 2014 at 16:43
18

This solution shows an active character approach, which (though heavy in the setup) will allow one to have cap letter automatically colorized. But because active letters will tend to break macros, I provide the means to disable it. This revised solution provides the following macros:

\capcoloron[color] turns all cap letters to this color (default red)

\capcoloroff turns off active characters and restores original cap-letter definitions

\coloron{letter}{color} turns just this [inactive] letter active and sets it to the specified color

\coloroff{letter} turns off just this active character, and restores its original definition.

The only quirk is that to change the color of a given capital letter that is already active, one must first turn the color off, and then turn it on again. Here is my MWE:

\documentclass{article}
\usepackage{xcolor}
\usepackage{stringstrings}

\let\sva A\let\svb B\let\svc C\let\svd D\let\sve E\let\svf F\let\svg G
\let\svh H\let\svi I\let\svj J\let\svk K\let\svl L\let\svm M\let\svn N
\let\svo O\let\svp P\let\svq Q\let\svr R\let\svs S\let\svt T\let\svu U
\let\svv V\let\svw W\let\svx X\let\svy Y\let\svz Z
\catcode`A=\active\catcode`B=\active\catcode`C=\active\catcode`D=\active
\catcode`E=\active\catcode`F=\active\catcode`G=\active\catcode`H=\active
\catcode`I=\active\catcode`J=\active\catcode`K=\active\catcode`L=\active
\catcode`M=\active\catcode`N=\active\catcode`O=\active\catcode`P=\active
\catcode`Q=\active\catcode`R=\active\catcode`S=\active\catcode`T=\active
\catcode`U=\active\catcode`V=\active\catcode`W=\active\catcode`X=\active
\catcode`Y=\active\catcode`Z=\active
\newcommand\colorcapon[1][red]{%
  \catcode`A=\active\def A{\textcolor{#1}{\sva}}%
  \catcode`B=\active\def B{\textcolor{#1}{\svb}}%
  \catcode`C=\active\def C{\textcolor{#1}{\svc}}%
  \catcode`D=\active\def D{\textcolor{#1}{\svd}}%
  \catcode`E=\active\def E{\textcolor{#1}{\sve}}%
  \catcode`F=\active\def F{\textcolor{#1}{\svf}}%
  \catcode`G=\active\def G{\textcolor{#1}{\svg}}%
  \catcode`H=\active\def H{\textcolor{#1}{\svh}}%
  \catcode`I=\active\def I{\textcolor{#1}{\svi}}%
  \catcode`J=\active\def J{\textcolor{#1}{\svj}}%
  \catcode`K=\active\def K{\textcolor{#1}{\svk}}%
  \catcode`L=\active\def L{\textcolor{#1}{\svl}}%
  \catcode`M=\active\def M{\textcolor{#1}{\svm}}%
  \catcode`N=\active\def N{\textcolor{#1}{\svn}}%
  \catcode`O=\active\def O{\textcolor{#1}{\svo}}%
  \catcode`P=\active\def P{\textcolor{#1}{\svp}}%
  \catcode`Q=\active\def Q{\textcolor{#1}{\svq}}%
  \catcode`R=\active\def R{\textcolor{#1}{\svr}}%
  \catcode`S=\active\def S{\textcolor{#1}{\svs}}%
  \catcode`T=\active\def T{\textcolor{#1}{\svt}}%
  \catcode`U=\active\def U{\textcolor{#1}{\svu}}%
  \catcode`V=\active\def V{\textcolor{#1}{\svv}}%
  \catcode`W=\active\def W{\textcolor{#1}{\svw}}%
  \catcode`X=\active\def X{\textcolor{#1}{\svx}}%
  \catcode`Y=\active\def Y{\textcolor{#1}{\svy}}%
  \catcode`Z=\active\def Z{\textcolor{#1}{\svz}}%
}
\def\colorcapoff{%
  \catcode`A=11\let A\sva%
  \catcode`B=11\let B\svb%
  \catcode`C=11\let C\svc%
  \catcode`D=11\let D\svd%
  \catcode`E=11\let E\sve%
  \catcode`F=11\let F\svf%
  \catcode`G=11\let G\svg%
  \catcode`H=11\let H\svh%
  \catcode`I=11\let I\svi%
  \catcode`J=11\let J\svj%
  \catcode`K=11\let K\svk%
  \catcode`L=11\let L\svl%
  \catcode`M=11\let M\svm%
  \catcode`N=11\let N\svn%
  \catcode`O=11\let O\svo%
  \catcode`P=11\let P\svp%
  \catcode`Q=11\let Q\svq%
  \catcode`R=11\let R\svr%
  \catcode`S=11\let S\svs%
  \catcode`T=11\let T\svt%
  \catcode`U=11\let U\svu%
  \catcode`V=11\let V\svv%
  \catcode`W=11\let W\svw%
  \catcode`X=11\let X\svx%
  \catcode`Y=11\let Y\svy%
  \catcode`Z=11\let Z\svz%
}
\newcommand\coloron[2]{%
  \if\sva#1\catcode`A=\active\def A{\textcolor{#2}{\sva}}\else%
  \if\svb#1\catcode`B=\active\def B{\textcolor{#2}{\svb}}\else%
  \if\svc#1\catcode`C=\active\def C{\textcolor{#2}{\svc}}\else%
  \if\svd#1\catcode`D=\active\def D{\textcolor{#2}{\svd}}\else%
  \if\sve#1\catcode`E=\active\def E{\textcolor{#2}{\sve}}\else%
  \if\svf#1\catcode`F=\active\def F{\textcolor{#2}{\svf}}\else%
  \if\svg#1\catcode`G=\active\def G{\textcolor{#2}{\svg}}\else%
  \if\svh#1\catcode`H=\active\def H{\textcolor{#2}{\svh}}\else%
  \if\svi#1\catcode`I=\active\def I{\textcolor{#2}{\svi}}\else%
  \if\svj#1\catcode`J=\active\def J{\textcolor{#2}{\svj}}\else%
  \if\svk#1\catcode`K=\active\def K{\textcolor{#2}{\svk}}\else%
  \if\svl#1\catcode`L=\active\def L{\textcolor{#2}{\svl}}\else%
  \if\svm#1\catcode`M=\active\def M{\textcolor{#2}{\svm}}\else%
  \if\svn#1\catcode`N=\active\def N{\textcolor{#2}{\svn}}\else%
  \if\svo#1\catcode`O=\active\def O{\textcolor{#2}{\svo}}\else%
  \if\svp#1\catcode`P=\active\def P{\textcolor{#2}{\svp}}\else%
  \if\svq#1\catcode`Q=\active\def Q{\textcolor{#2}{\svq}}\else%
  \if\svr#1\catcode`R=\active\def R{\textcolor{#2}{\svr}}\else%
  \if\svs#1\catcode`S=\active\def S{\textcolor{#2}{\svs}}\else%
  \if\svt#1\catcode`T=\active\def T{\textcolor{#2}{\svt}}\else%
  \if\svu#1\catcode`U=\active\def U{\textcolor{#2}{\svu}}\else%
  \if\svv#1\catcode`V=\active\def V{\textcolor{#2}{\svv}}\else%
  \if\svw#1\catcode`W=\active\def W{\textcolor{#2}{\svw}}\else%
  \if\svx#1\catcode`X=\active\def X{\textcolor{#2}{\svx}}\else%
  \if\svy#1\catcode`Y=\active\def Y{\textcolor{#2}{\svy}}\else%
  \if\svz#1\catcode`Z=\active\def Z{\textcolor{#2}{\svz}}\else%
  \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi%
}
\newcommand\coloroff[1]{\catcode`#1=11%
  \edef\tmp{\detokenize{#1}}%
  \caselower[q]{\tmp}%
  \expandafter\let\expandafter#1\csname sv\thestring\endcsname%
}
\catcode`A=11\catcode`B=11\catcode`C=11\catcode`D=11\catcode`E=11
\catcode`F=11\catcode`G=11\catcode`H=11\catcode`I=11\catcode`J=11
\catcode`K=11\catcode`L=11\catcode`M=11\catcode`N=11\catcode`O=11
\catcode`P=11\catcode`Q=11\catcode`R=11\catcode`S=11\catcode`T=11
\catcode`U=11\catcode`V=11\catcode`W=11\catcode`X=11\catcode`Y=11
\catcode`Z=11

\parskip 1em

\begin{document}

\colorcapon[cyan]
\verb|\colorcapon[color]| will change all caps to the specified color\\
A Test of The Active Method (\verb|Even in \Verbatim|)

\colorcapoff
\verb|\colorcapoff| will restore all things to the original LaTeX setting\\
A Test of The Active Method

\coloron{M}{blue}\coloron{A}{red}\coloron{T}{orange}
\verb|\coloron{letter}{color}| will turn an inactive letter active with the
specified color, done here to letters ``M'', ``A'', and ``T'':\\
A Test of The Active Method

\coloroff{A}
\verb|\coloroff{letter}| will restore that letter to the original LaTeX
setting, here done to the letter ``A'':\\
A Test of The Active Method

To change The color an already active letter, one must first turn the color off
and then set the color anew, as done here to the letter ``T'':\\
\coloroff{T}\coloron{T}{green}
A Test of The Active Method
\end{document}

enter image description here


ORIGINAL SOLUTION:

This shows the traditional and dangerous active character approach. The active approach takes a fair amount of "setup" code, but then will automatically change the cap letter colors upon use.

Because it is dangerous, I provide the means to enter and exit the active approach with \colorcapon and \colorcapoff. I've only set up 3 letters... but the other 23 follow in a similar manner.

\documentclass{article}
\usepackage{xcolor}
\begin{document}
TRADITIONAL APPROACH:

\textcolor{red}{A} letter can have its color \textcolor{blue!60}{C}hanged
with the \textcolor{cyan!80}{U}se of \verb|\textcolor|.\vspace{2em}

ACTIVE CHARACTER APPROACH

\let\sva A
\let\svc C
\let\svu U
\catcode`A=\active
\catcode`C=\active
\catcode`U=\active
\def\colorcapon{%
  \catcode`A=\active\def A{\textcolor{red}{\sva}}%
  \catcode`C=\active\def C{\textcolor{blue!60}{\svc}}%
  \catcode`U=\active\def U{\textcolor{cyan!80}{\svu}}%
}
\def\colorcapoff{%
  \catcode`A=11\let A\sva%
  \catcode`C=11\let C\svc%
  \catcode`U=11\let U\svu%
}
\catcode`A=11
\catcode`C=11
\catcode`U=11

\colorcapon
A letter can have its color Changed with the Use of\\
\verb|\textcolor.  Wow.  And I can Use it in verbatim|.\vspace{2em}\colorcapoff


RESTORED TO ORIGINAL

A letter can have its color Changed with the Use of \verb|\textcolor|.

\end{document}

enter image description here

5
  • Impressive :) I'm going to read about these catcodes and what they do. Is there a way to select caps in a more generic manner than defining them individually?
    – Jonathan H
    Apr 24, 2014 at 10:54
  • 1
    @Sh3ljohn I'm thinking about that, but it requires another trick that I still haven't unraveled. If I obtain it, I will post. Apr 24, 2014 at 10:59
  • @Sh3ljohn Please see revision. Apr 24, 2014 at 13:36
  • Thanks, I'm going to mark it as the answer, but I find it a bit hackish personally. There ought to be a proper way of iterating over the chars of a string, checking for case, and modify those characters conditionally.
    – Jonathan H
    Apr 24, 2014 at 14:31
  • @Sh3ljohn There may be a better way, but it gets complicated, and problems arise when the argument passed to a macro is active, but the macro was defined when that character was not active. When that happens, things that look the same in the code will actually fail a comparison test, because they possess different catcode designations. Apr 24, 2014 at 14:49
3

This is a snippet programmed in LuaLaTeX, a new command \capme takes the argument, uses Lua and converts preselected characters via regular expression and unicode.utf8.gsub function to a new command \colorme. I tried to implement change of common words as well as marked one (words preceeded by a { letter, e.g. \textit{Ňouma}). I have extended a common series of uppercase letters (A to Z) by some letters with diacritics to demonstrate its additional feature.

I have found a way how to disobey \noexpand command I frequently used in my previous LuaTeX examples. I am extending the individual commands in a local group, in this example it is the \textit command. However, it would need more complex example and data if this is the right way how to save typing time.

We run lualatex mal-capitalization.tex, I enclose the file and a preview of the result.

% lualatex mal-capitalization.tex
\documentclass[a4paper]{article}
%\usepackage{fontspec} % It also loads Latin Modern.
%\usepackage{luacode}
\usepackage{luatextra} % a recommended way of loading luacode (and fontspec) package
\pagestyle{empty}
\usepackage{xcolor}

\begin{document}
\begin{luacode*}
selection="[%uČĎŇŘŠŤŽ]" -- the characters we consider to be coloured
function capme(text)
text=" "..text -- the first letter of a string is also considered for change
text=unicode.utf8.gsub(text, "([%s{])("..selection..")", "%1\\colorme{%2}")
text=unicode.utf8.sub(text,2) -- delete that extra space
print(text) -- a new text written to the terminal
tex.print(text) -- deliver the result back to TeX
end -- function capme
\end{luacode*}

\def\capme#1{%
    % We neither need \noexpand\textit nor \noexpand{#1} and \\textit.
    \begingroup % Let's redefining begin!
    \let\oldtextit=\textit
    \def\textit##1{\noexpand\oldtextit{##1}}
    \directlua{capme([[#1]])}
      \endgroup % \textit returns to its common definition.
    }
\def\colorme#1{{\color{red}\bfseries#1}}

% A small demonstration of using it.
Hello World! \capme{Hello Capitalized WORLD!} 
Several words with diacritics: \capme{Čenich. \textit{Ňouma.} 
Ďagilev. Šiška. Živočich.} I'm back in \textit{common} text.
\end{document}

This is an example of using this snippet: common words and several words starting with a diacritical letter.

1

It is possible using OPmac macros:

\input opmac

\def\setupclr #1{\ifx\relax#1\else \replacestrings{#1}{\clr{#1}}\expandafter\setupclr\fi}
\def\clrstring#1{\def\tmpb{#1}\setupclr ABCDEFGHIJKLMNOPQRSTUVWXYZ\relax \tmpb}
\def\clr#1{{\localcolor\Red#1}}

\clrstring{Once Upon a Time.}

\bye

Edit: If capital letters in groups must be processed too, then one can use the \repl macro from \tl_replace_all:Nnn recurse subgroups and define

\def\replX#1{\ifnum\uccode`#1=`#1 \clr{#1}\else #1\fi}
1
  • Try \clrstring{Once Upon a {\it Time}.} and \colorcap{Once Upon a \emph{Time}.}
    – egreg
    Jul 1, 2017 at 18:12

You must log in to answer this question.

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