Strongly based on my answer at How to insert a symbol to the beginning of a line for which a word appears?. However, I had to extend the logic to handle multiple color assignments. Syntax is multiple invocations of \WordsToNote{space separated list}{color}
and then \NoteWords{multiple paragraph input}
Macros in the input are limited to style (e.g., \textit
) and size (e.g., \small
) changes. Otherwise, only plain text is accepted.
As detailed in the referenced answer, I adapt my titlecaps
package, which normally capitalizes the first letter of each word in its argument, with a user-specified list of exceptions. Here, instead of capitalizing the words, I leave them intact. However, I trap the user-specified word exceptions and use them to set a different color.
In this extension of that method, I had to revise two titlecaps
macros: \titlecap
and \seek@lcwords
.
The method cannot handle word subsets, but it can ignore punctuation.
EDITED to fix bug when flagged word appears with punctuation, and issue with first word of paragraphs.
\documentclass{article}\usepackage{titlecaps}\makeatletter\renewcommand\titlecap[2][P]{% \digest@sizes% \if T\converttilde\def~{ }\fi% \redefine@tertius% \get@argsC{#2}% \seek@lcwords{#1}% \if P#1% \redefine@primus% \get@argsC{#2}% \protected@edef\primus@argi{\argi}% \else% \fi% \setcounter{word@count}{0}% \redefine@secundus% \def\@thestring{}% \get@argsC{#2}% \if P#1\protected@edef\argi{\primus@argi}\fi% \whiledo{\value{word@count} < \narg}{% \addtocounter{word@count}{1}% \if F\csname found@word\roman{word@count}\endcsname% \notitle@word{\csname arg\roman{word@count}\endcsname}% \expandafter\protected@edef\csname% arg\roman{word@count}\endcsname{\@thestring}% \else \notitle@word{\csname arg\roman{word@count}\endcsname}% \expandafter\protected@edef\csname% arg\roman{word@count}\endcsname{\color{% \csname color\romannumeral\value{word@count}\endcsname}% \@thestring\color{black}{}}% \fi% }% \def\@thestring{}% \setcounter{word@count}{0}% \whiledo{\value{word@count} < \narg}{% \addtocounter{word@count}{1}% \ifthenelse{\value{word@count} = 1}% {}{\add@space}% \protected@edef\@thestring{\@thestring% \csname arg\roman{word@count}\endcsname}% }% \let~\SaveHardspace% \@thestring% \restore@sizes%\un@define}% SEARCH TERTIUS CONVERTED ARGUMENT FOR LOWERCASE WORDS, SET FLAG% FOR EACH WORD (T = FOUND IN LIST, F= NOT FOUND IN LIST)\renewcommand\seek@lcwords[1]{%\kill@punct% \setcounter{word@count}{0}% \whiledo{\value{word@count} < \narg}{% \addtocounter{word@count}{1}% \protected@edef\current@word{% \csname arg\romannumeral\value{word@count}\endcsname}% \def\found@word{F}% \setcounter{lcword@index}{0}% \expandafter\def\csname% found@word\romannumeral\value{word@count}\endcsname{F}% \whiledo{\value{lcword@index} < \value{lc@words}}{% \addtocounter{lcword@index}{1}% \protected@edef\current@lcword{% \csname lcword\romannumeral\value{lcword@index}\endcsname}%%% THE FOLLOWING THREE LINES ARE FROM DAVID CARLISLE \protected@edef\tmp{\noexpand\scantokens{\def\noexpand\tmp% {\noexpand\ifthenelse{\noexpand\equal{\current@word}{\current@lcword}}}}}% \tmp\ifhmode\unskip\fi\tmp%% {\expandafter\def\csname% found@word\romannumeral\value{word@count}\endcsname{T}% \expandafter\protected@edef\csname color\romannumeral\value{word@count}\endcsname{% \csname CoLoR\csname lcword\romannumeral\value{lcword@index}\endcsname\endcsname}% \setcounter{lcword@index}{\value{lc@words}}% }% {}% }% }%\if P#1\def\found@wordi{F}\fi%\restore@punct%}\makeatother\usepackage{xcolor}\newcommand\WordsToNote[2]{\Addlcwords{#1}\edef\assignedcolor{#2}% \assigncolor#1 \relax\relax}\def\assigncolor#1 #2\relax{% \expandafter\edef\csname CoLoR#1\endcsname{\assignedcolor}% \ifx\relax#2\else\assigncolor#2\relax\fi%}\newcommand\NoteWords[1]{\NoteWordsHelp#1\par\relax}\long\def\NoteWordsHelp#1\par#2\relax{% \titlecap[p]{#1}% \ifx\relax#2\else\par\NoteWordsHelp#2\relax\fi%}\begin{document}\WordsToNote{foo bar at}{red}\WordsToNote{Nulla dolor nulla}{cyan}\WordsToNote{amet est et}{orange}\WordsToNote{Lorem Ut ut felis}{green}\NoteWords{\textbf{Lorem ipsum dolor foo sit amet, bar consectetuer adipiscing elit}. Utpurus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. Curabiturdictum gravida mauris. Nam arcu libero, nonummy eget,consectetuer id, vulputate a, magna. Donec vehicula augue euneque. Pellentesque habitant morbi tristique senectus et netus etmalesuada fames ac turpis egestas. Mauris ut leo. Cras viverra metusrhoncus sem. \textit{Nulla et lectus foo} vestibulum urna fringilla ultrices.Phasellus eu tellus sit amet tortor gravida placerat. Integer sapienest, iaculis in, pretium quis, viverra ac, nunc. Praesent eget semvel leo ultrices bibendum. \scshape Aenean faucibus. Morbi dolor nulla,malesuada eu, pulvinar at, mollis ac, nulla. Curabitur auctor sempernulla. Donec varius orci eget risus. \upshape Duis nibh mi, congue eu,accumsan eleifend, bar sagittis quis, diam. Duis eget orci sit amet orcidignissim rutrum.\textsf{Lorem ipsum dolor sit amet}, consectetuer adipiscing elit. Utpurus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. Curabiturdictum gravida mauris. Nam arcu libero, nonummy eget,consectetuer id, foo vulputate a, magna. Donec vehicula augue euneque. Pellentesque habitant morbi tristique senectus et netus etmalesuada fames ac turpis egestas. Mauris ut leo. Cras viverra metusrhoncus sem. Nulla et lectus vestibulum urna fringilla ultrices.Phasellus eu tellus sit amet tortor gravida placerat. Integer sapienest, iaculis in, pretium quis, viverra ac, bar nunc. Praesent eget semvel leo ultrices bibendum. Aenean faucibus. Morbi dolor nulla,malesuada eu, pulvinar at, mollis ac, nulla. Curabitur auctor sempernulla. Donec varius orci eget risus. Duis nibh mi, congue eu,accumsan eleifend, sagittis quis, diam. \Large Duis eget orci sit amet orcidignissim rutrum.\normalsize}\end{document}
Image may be NSFW.
Clik here to view.