![¿Cómo definir _o_ redefinir un comando (mezclando \providecommand + \renewcommand)?](https://rvso.com/image/305894/%C2%BFC%C3%B3mo%20definir%20_o_%20redefinir%20un%20comando%20(mezclando%20%5Cprovidecommand%20%2B%20%5Crenewcommand)%3F.png)
En algunas situaciones desearía que hubiera una manera de definir un comando \tmp
para que
- si
\tmp
no existe: Definido\tmp
- si
\tmp
sale: Redefinir\tmp
Mi enfoque actual es simplemente usar \newcommand
o \renewcommand
. Sin embargo, esto significa que a menudo tengo que cambiar de una versión a otra si reordeno mis documentos y, a veces, limita la reutilización general de mi código.
Enesta preguntaAprendí sobre \providecommand
, lo que casi resuelve mi problema: se puede usar independientemente de si \tmp
está definido, pero solo se define en la primera aparición y no se sobrescribe. Esto me lleva al ingenuo intento:
\newcommand{\overwritecommand}[2]{
\providecommand{#1}{#2}
\renewcommand{#1}{#2}
}
Sin embargo, este enfoque obviamente no es lo suficientemente general:
% 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.
¿Hay alguna otra manera de lograr eldefinir o sobrescribir¿comportamiento?
Respuesta1
Sí, existe un método:
\newcommand{\declarecommand}[1]{\providecommand{#1}{}\renewcommand{#1}}
¿Por qué funciona? Porque TeX usa expansión macro y es irrelevante lo que \providecommand
define #1
ser, si #1
no se definió, porque lo redefines inmediatamente.
Ahora que sabes cómo hacerlo, prueba
\declarecommand{\box}[1]{\fbox{#1}}
¡Y disfruta del naufragio!
Alláesuna razón por la cual LaTeX no proporciona una \declarecommand
función: ustedDEBEtenga en cuenta si está redefiniendo un comando existente.
Si desea permitir el opcional *
, entonces
\makeatletter
\newcommand\declarecommand{\@star@or@long\@declarecommand}
\newcommand\@declarecommand[1]{%
\provide@command{#1}{}%
\renew@command{#1}%
}
\makeatother
servirá.
Respuesta2
Entiendo que lo necesitas \def
pero con parámetros como \newcommand
. Es posible definir el nuestro\newcommand
, que ignora si la secuencia de control definida tiene un significado. Por ejemplo podemos usar el código deesta página:
\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}}
Respuesta3
Como ya se han mostrado los ejemplos clásicos, simplemente agregaré la xparse
forma, que es bastante fácil de usar:
\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}