如何将字符串的第一次出现排版得与后面的出现不同?

如何将字符串的第一次出现排版得与后面的出现不同?

我的问题类似于这个问题但我需要一个取决于输入的解决方案。我想要一个命令\propername{},它将第一个参数的第一次出现写成斜体,否则为正常。

我尝试使用etoolbox-package 来解决它,但迄今为止没有成功。

\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}输出first: foobarpropernamefoobar

最后我想要的是这样的:

输入:\propername{foobar} bar \propername{foobar}

输出: ”福巴酒吧 foobar”

挑战在于我需要为每个可能的输入值设置一个切换开关。

答案1

您可以为这些命令定义一个包装器。这将定义以斜体打印文本的命令全局重新定义相同的命令以正常打印。无需为每个这样的命令定义切换。

\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}

在此处输入图片描述

如果要追求该\propername策略,请在第一次执行命令时(当内部宏仍未定义时)全局定义一个内部宏。

\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}

输出是一样的。

您可以扩展代码来计算发生次数。

\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}

在此处输入图片描述

答案2

我对 Tex 没有经验,但我可以像这样解决它:

% 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}}
}

答案3

一种方法是使用计数器机制。以下代码:

  1. 定义一个新命令\myitalic,首先检查您作为参数传递的单词是否是第一次使用,如果是,则将其变为斜体。
  2. 然后定义使用上述定义的实际命令。在这里我们定义一个我们想要的正确名称的计数器只有当它不存在时。强调的部分很重要,否则每次出现该词时都会定义相同的计数器,从而产生错误。我们在此 if 条件中将新定义的计数器的值设置为 0。因此,文本在第一次使用时会显示为斜体,否则将以正常字体打印。对于后者,我们每次使用时都会将计数器的值增加一个单位。因此,专有名词在第二次使用时会避开 if 条件。

附言:这不是你要求的,但我们可以打印专有名词被使用的次数伟大的\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

此代码的主要优点是它不需要任何包。其中的所有内容都是纯 LaTeX。:)

相关内容