コマンドを定義または再定義するにはどうすればよいですか (\providecommand + \renewcommand を混在させる)?

コマンドを定義または再定義するにはどうすればよいですか (\providecommand + \renewcommand を混在させる)?

状況によっては、コマンドを定義する方法があればいい\tmpのにと思うことがあります。

  • 存在しない場合\tmp: 定義済み\tmp
  • \tmp終了する場合: 再定義\tmp

\newcommand私の現在のアプローチは、単にまたは を使用することです\renewcommand。ただし、これは、ドキュメントを並べ替える場合に、あるバージョンから別のバージョンに変更する必要があり、コード全体の再利用性が制限される場合があることを意味します。

この質問私は について学びました\providecommand。これで私の問題はほぼ解決しました。 は が定義されているかどうかに関係なく使用できます\tmpが、最初の出現時にのみ を定義し、上書きしません。これが私を素朴な試みへと導きました。

\newcommand{\overwritecommand}[2]{
  \providecommand{#1}{#2}
  \renewcommand{#1}{#2}
}

しかし、このアプローチは明らかに十分に汎用的ではありません。

% it works for
\overwritecommand{\tmp}{test}

% but not for commands with arguments like
\overwritecommand{\tmp}[1]{test: #1} 
% Error: You can't use `macro parameter character #' in horizontal mode.

他に達成する方法はありますか?定義または上書きする行動?

答え1

はい、方法はあります:

\newcommand{\declarecommand}[1]{\providecommand{#1}{}\renewcommand{#1}}

なぜそれが機能するのでしょうか? TeX はマクロ展開を使用するため、定義されていない場合はすぐに再定義されるため、何が\providecommand定義されるかは関係ありません。#1#1

やり方がわかったら、試してみましょう

\declarecommand{\box}[1]{\fbox{#1}}

そして難破船を楽しんでください!

そこにはLaTeXが関数を提供しない理由\declarecommandしなければならない既存のコマンドを再定義しているかどうかに注意してください。

オプションを許可したい場合は*

\makeatletter
\newcommand\declarecommand{\@star@or@long\@declarecommand}
\newcommand\@declarecommand[1]{%
  \provide@command{#1}{}%
  \renew@command{#1}%
}
\makeatother

します。

答え2

\defのようなパラメータが必要なのは理解していますが\newcommand、定義された制御シーケンスが意味を持つかどうかを無視する独自のものを定義することは可能です\newcommand。たとえば、次のコードを使用できます。このページ:

\def\newcommand#1{\isnextchar[{\newcommandA#1}{\newcommandA#1[0]}}
\def\newcommandA#1[#2]{\edef\tmpp{\ifcase#2%
   \or1\or12\or123\or1234\or12345\or123456\or1234567\or12345678\or123456789\fi}%
   \edef\tmpp{\expandafter\addhashs\tmpp.}%
   \isnextchar[{\newcommandB#1}{\long\expandafter\def\expandafter#1\tmpp}%
}
\def\newcommandB#1[#2]{%
   \def#1{\isnextchar[{\runcommand#1}{\runcommand#1[#2]}}%
   \long\expandafter\def\csname\string#1X\expandafter\endcsname\tmpp
}
\def\addhashs#1{\ifx.#1\else #####1\expandafter\addhashs\fi}
\long\def\runcommand#1[#2]{\csname\string#1X\endcsname{#2}} 

答え3

xparse典型的な例はすでに示されているので、ここでは非常にユーザーフレンドリーな方法を追加します。

\documentclass{article}
\usepackage{xparse}
\DeclareDocumentCommand{\foo}{m}
 {Foo: #1}
\begin{document}

\foo{bar}

\DeclareDocumentCommand{\foo}{om}
 {\IfNoValueTF{#1}%
   {Bar: no optional, just #2}%
   {Bar: optional = #1, plus #2}%
 }%

\foo{Baz}

\foo[Bar]{Baz}

\end{document}

関連情報