3

My question is similar to this question but I need a solution depending on the input. I'd like to have a command \propername{}, which writes the very first occurrence of the first argument in italic, otherwise normal.

I tried to solve it with the etoolbox-package, so far without success.

\newcommand{\propername}[1]{%
    \providetoggle{propername#1}
    \iftoggle{propername#1}{not first: #1}
    \nottoggle{propername#1}{first: #1}
    \toggletrue{propername#1}% switches to true after first occurrence!
}

\propername{foobar} output first: foobarpropernamefoobar

In the end I'd like to have something like this:

Input: \propername{foobar} bar \propername{foobar}

Output: "foobar bar foobar"

The challenge is that I need a toggle for each possible input value.

Niranjan
  • 3,435
phip1611
  • 131
  • 4

3 Answers3

1

You can define a wrapper for these commands. This defines the command to print the text in italic and globally redefines the same command to print it normally. No need to define toggles for each such command.

\documentclass{article}

\newcommand{\makespecialcommand}[2]{% \newcommand{#1}{\textit{#2}\gdef#1{#2}}% }

\makespecialcommand{\foo}{foo} \makespecialcommand{\baz}{baz}

\begin{document}

Here \foo\ is called and \foo\ is called again.

\begin{quote} Now \baz\ is called in an environment. \end{quote}

And now \baz\ is called again.

\end{document}

enter image description here

If you want to pursue the \propername strategy, globally define an internal macro when the command is executed the first time (when the internal macro is still undefined).

\documentclass{article}

\newcommand{\propername}[1]{% \ifcsname\detokenize{#1}@used\endcsname #1% \else \textit{#1}% \global\expandafter\let\csname\detokenize{#1}@used\endcsname\empty \fi }

\begin{document}

Here \propername{foo} is called and \propername{foo} is called again.

\begin{quote} Now \propername{baz} is called in an environment. \end{quote}

And now \propername{baz} is called again.

\end{document}

The output is the same.

You can extend the code to count the occurrences.

\documentclass{article}

\newcommand{\propername}[1]{% \ifcsname\detokenize{#1}@used\endcsname #1% \global\expandafter\xdef\csname\detokenize{#1}@used\endcsname{% \the\numexpr\csname\detokenize{#1}@used\endcsname+1\relax }% \else \textit{#1}% \expandafter\gdef\csname\detokenize{#1}@used\endcsname{1}% \fi } \newcommand{\nameoccurred}[1]{% \ifcsname\detokenize{#1}@used\endcsname #1 occurred \csname\detokenize{#1}@used\endcsname\space times'' \else#1 didn't appear'' \fi }

\begin{document}

Here \propername{foo} is called and \propername{foo} is called again.

\begin{quote} Now \propername{baz} is called in an environment. \end{quote}

And now \propername{baz} is called again and \propername{baz} again.

\nameoccurred{foo}

\nameoccurred{baz}

\nameoccurred{gnu}

\end{document}

enter image description here

egreg
  • 1,121,712
0

I'm not experienced with Tex, but I could solve it like this:

% Writes the first occurrence of a given word in italic, otherwise normal.
\newcommand{\propername}[1]{%
    \providebool{propername#1}
    \ifthenelse{\boolean{propername#1}}
        % not first occurrence
        {#1}
        % first occurrence
        {\textit{#1} \setboolean{propername#1}{true}}
}
phip1611
  • 131
  • 4
0

One approach would be to use the counter mechanism. The following code:

  1. defines a new command \myitalic which first checks if the word you have passed as an argument is used for the first time or not, if yes it italicizes it.
  2. then defines our actual command which uses the above definition. Here we define a counter of our desired proper name only if it doesn't exist. The emphasized part is important, otherwise at every instance of that word the same counter is defined, which produces an error. We set the value of that newly defined counter to 0 in this if-condition. Because of this; the text is italicized when it is used for the first time and it is printed in the normal font otherwise. For the later we increase the value of our counter by one unit each time it gets used. The proper noun escapes the if-condition from the second usage because of this.

PS: Not something that you asked for, but we can print how many times a proper noun has been used with the mighty \the.

\documentclass{article}
\newcommand{\myitalic}[1]{%
  \ifnum\value{#1}=0%
    \textit{#1}%
  \else
    #1%
  \fi
}%
\makeatletter
\newcommand{\propername}[1]{%
  \ifcsname c@#1\endcsname
    \relax
  \else
    \newcounter{#1}%
  \fi
  \myitalic{#1}%
  \addtocounter{#1}{1}%
}
\makeatother

\begin{document} \propername{foobaz} \propername{foobaz} \propername{foobaz} \propername{foobaz} \propername{foobaz}.

`foobaz' was used \thefoobaz\ times.

\propername{bazfoo} \propername{bazfoo} \propername{bazfoo}.

`bazfoo' was used \thebazfoo\ times. \end{document}

1

A major benefit of this code is it doesn't require any package. Every thing in it is plain-LaTeX. :)

Niranjan
  • 3,435
  • There are several counters available, but this is not a reason to abuse them for just setting them >0 (unless you really want to count their appearance). Macros are cheaper. – egreg Dec 10 '21 at 17:10
  • Can you explain any problem-cases with this approach? – Niranjan Dec 10 '21 at 17:15
  • I didn't understand "but this is not a reason to abuse them for just setting them >0". I didn't set it to zero. I just checked it's value and set a conditional if it's zero. – Niranjan Dec 10 '21 at 17:16
  • No real problem, except wasting resources. You basically get different behavior if the counter is 0 or greater than 0, don't you? If the number of times is not needed, you're wasting a counter just to set it greater than 0. – egreg Dec 10 '21 at 17:16
  • Okay, I would say everything in the code has been used, so nothing is really getting wasted as far as this answer is concerned. If the OP doesn't want counting at all, then maybe your answer is a better alternative. – Niranjan Dec 10 '21 at 17:18