Como definir uma macro com vários parâmetros opcionais?

Como definir uma macro com vários parâmetros opcionais?

Depois que uma macro funcionou, tentei melhorá-la tornando alguns parâmetros opcionais. Infelizmente a macro não funciona mais. Em vez disso, estou recebendo erros que não entendo, por exemplo:

LaTeX Warning: Label `####5' multiply defined.
LaTeX Warning: Label `####5' multiply defined.
! LaTeX Error: \fLab undefined.
! Illegal parameter number in definition of \fLab.
! Illegal parameter number in definition of \reserved@a.
! LaTeX Error: \fCap undefined.

...e assim por diante. O último código que tentei ficou assim:

%% Graphics figure with caption and label
% [1:placement,] 2:relative width, 3:file name[, 4:caption[, 5:label]]
\newcommand{\figCapLab}[5][htbp]{%
\ifthenelse{\equal{#5}{}}%
{\renewcommand{\fLab}{}}%
{\renewcommand{\fLab}{\label{##5}}}%
\ifthenelse{\equal{#4}{}}%
{\renewcommand{\fCap}{\fLab}}%
{\renewcommand{\fCap}{\caption{\fLab{\small{}##4}}}}%
\begin{figure}[#1]%
\centering%
\begin{minipage}[t]{#2\textwidth}%
\includegraphics[width=\textwidth]{#3}% is width of surrounding minipage
\fCap%
\end{minipage}%
\end{figure}
}
%% Graphics figure with caption
% [1:placement,] 2:relative width, 3:file name, 4:caption
\newcommand{\figCap}[4]{%
\ifthenelse{\equal{#1}{}}%
{\figCapLab{#2}{#3}{#4}{}}%
{\figCapLab[#1]{#2}{#3}{#4}{}}%
}
%% Graphics figure with label
% [1:placement,] 2:relative width, 3:file name, 4:label
\newcommand{\figLab}[4]{%
\ifthenelse{\equal{#1}{}}%
{\figCapLab{#2}{#3}{}{#4}}%
{\figCapLab[#1]{#2}{#3}{}{#4}}%
}

Quem pode explicar o que deu errado?

Pessoas que gostam de exemplos completos deveriam adicionar este prólogo:

\documentclass[a4paper,twoside]{report}
\usepackage{german}
\usepackage[latin1]{inputenc}
\usepackage{a4}
\usepackage{amsmath}
\usepackage{url}
\usepackage{graphicx}
\usepackage{ifthen}

... e este epílogo:

\begin{document}
See \ref{foo}.
\figCapLab{0.9}{whatever.pdf}{Caption}{foo}
\end{document}

Responder1

Quando eu obedeço às suas vagas instruções para criar eu mesmo um exemplo compilável que exiba o comportamento errôneo

\documentclass[a4paper,twoside]{report}
\usepackage{german}
\usepackage[latin1]{inputenc}
\usepackage{a4}
\usepackage{amsmath}
\usepackage{url}
\usepackage{graphicx}
\usepackage{ifthen}

%% Graphics figure with caption and label
% [1:placement,] 2:relative width, 3:file name[, 4:caption[, 5:label]]
\newcommand{\figCapLab}[5][htbp]{%
\ifthenelse{\equal{#5}{}}%
{\renewcommand{\fLab}{}}%
{\renewcommand{\fLab}{\label{##5}}}%
\ifthenelse{\equal{#4}{}}%
{\renewcommand{\fCap}{\fLab}}%
{\renewcommand{\fCap}{\caption{\fLab{\small{}##4}}}}%
\begin{figure}[#1]%
\centering%
\begin{minipage}[t]{#2\textwidth}%
\includegraphics[width=\textwidth]{#3}% is width of surrounding minipage
\fCap%
\end{minipage}%
\end{figure}
}
%% Graphics figure with caption
% [1:placement,] 2:relative width, 3:file name, 4:caption
\newcommand{\figCap}[4]{%
\ifthenelse{\equal{#1}{}}%
{\figCapLab{#2}{#3}{#4}{}}%
{\figCapLab[#1]{#2}{#3}{#4}{}}%
}
%% Graphics figure with label
% [1:placement,] 2:relative width, 3:file name, 4:label
\newcommand{\figLab}[4]{%
\ifthenelse{\equal{#1}{}}%
{\figCapLab{#2}{#3}{}{#4}}%
{\figCapLab[#1]{#2}{#3}{}{#4}}%
}

\begin{document}
See \ref{foo}.
\figCapLab{0.9}{whatever.pdf}{Caption}{foo}
\end{document}

, não recebo nenhum dos erros que você descreve, mas recebo:

LaTeX Warning: Reference `foo' on page 1 undefined on input line 43.


! LaTeX Error: \fLab undefined.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.44 \figCapLab{0.9}{whatever.pdf}{Caption}{foo}

? 
! Illegal parameter number in definition of \fLab.
<to be read again> 
                   5
l.44 \figCapLab{0.9}{whatever.pdf}{Caption}{foo}

? 

! LaTeX Error: \fCap undefined.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.44 \figCapLab{0.9}{whatever.pdf}{Caption}{foo}

? 
! Illegal parameter number in definition of \fCap.
<to be read again> 
                   4
l.44 \figCapLab{0.9}{whatever.pdf}{Caption}{foo}

? 

LaTeX Warning: File `whatever.pdf' not found on input line 44.


! Package pdftex.def Error: File `whatever.pdf' not found: using draft setting.


See the pdftex.def package documentation for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.44 \figCapLab{0.9}{whatever.pdf}{Caption}{foo}

? 
! Illegal parameter number in definition of \reserved@a.
<to be read again> 
                   4
l.44 \figCapLab{0.9}{whatever.pdf}{Caption}{foo}

? 
! Illegal parameter number in definition of \reserved@a.
<to be read again> 
                   5
l.44 \figCapLab{0.9}{whatever.pdf}{Caption}{foo}

? 
! You can't use `macro parameter character #' in restricted horizontal mode.
<argument> ...e : \ignorespaces \fLab {\small {}##
                                                  4}
l.44 \figCapLab{0.9}{whatever.pdf}{Caption}{foo}

? 
[1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./test.aux)

LaTeX Warning: There were undefined references.

Quando em vez disso eu faço:

\documentclass[a4paper,twoside]{report}
\usepackage{german}
\usepackage[latin1]{inputenc}
\usepackage{a4}
\usepackage{amsmath}
\usepackage{url}
\usepackage{graphicx}
\usepackage{ifthen}

% As later \renwecommand is done on these macros, 
% they should be defined: !!!!!!!!!!!!
\newcommand{\fLab}{}
\newcommand{\fCap}{}

%% Graphics figure with caption and label
%  #1: optional: placement
%  #2: non-optional: relative width
%  #3: non-optional: file name
%  #4: non-optional: in case not empty: caption
%  #5: non-optional: in case not empty: label
\newcommand{\figCapLab}[5][htbp]{%
\ifthenelse{\equal{#5}{}}%
{\renewcommand{\fLab}{}}%
{\renewcommand{\fLab}{\label{#5}}}% !!!!Don't double the hash!!!!
\ifthenelse{\equal{#4}{}}%
{\renewcommand{\fCap}{\fLab}}%
{\renewcommand{\fCap}{\caption{\fLab{\small{}#4}}}}% !!!!Don't double the hash!!!!
\begin{figure}[#1]%
\centering
\begin{minipage}[t]{#2\textwidth}%
\includegraphics[width=\textwidth]{#3}% is width of surrounding minipage
\fCap
\end{minipage}%
\end{figure}%%%%%%%
}
%% Graphics figure with caption
% [1:placement,] 2:relative width, 3:file name, 4:caption
\newcommand{\figCap}[4]{%
\ifthenelse{\equal{#1}{}}%
{\figCapLab{#2}{#3}{#4}{}}%
{\figCapLab[#1]{#2}{#3}{#4}{}}%
}
%% Graphics figure with label
% [1:placement,] 2:relative width, 3:file name, 4:label
\newcommand{\figLab}[4]{%
\ifthenelse{\equal{#1}{}}%
{\figCapLab{#2}{#3}{}{#4}}%
{\figCapLab[#1]{#2}{#3}{}{#4}}%
}

\begin{document}
See \ref{foo}.
\figCapLab{0.9}{example-grid-100x100pt.pdf}{Caption}{foo}
\end{document}

, não recebo nenhum erro ou aviso na segunda compilação.


A propósito 1:

eu não tenhotanto faz.pdfnas árvores texmf do meu sistema.

Se você deseja fornecer exemplos que processam imagens, você pode usar as imagens prontas para uso que os sistemas LaTeX modernos oferecem:

Por exemplo, a documentação do livro de Martin ScharrerPacote MWElista todas as imagens disponíveis devido a esse pacote. Com as plataformas TeX atuais e os lançamentos atuais doPacote MWE, as imagens podem ser utilizadas sem a necessidade de carregar o pacote porque estão integradas na árvore texmf e no banco de dados de nomes de arquivo.

A propósito 2:

Em circunstâncias normais você pode recuar linhas do código-fonte do TeX para melhorar a legibilidade. ;-) Isso ocorre porque quando (La)TeX começa a ler uma linha de entrada, o estado do aparelho de leitura está no estado N (nova linha), enquanto no estado N caracteres do código de categoria 10 (espaço) não serão tokenizados como fichas de espaço, mas não produzirá nenhuma ficha.

A propósito 3:

É uma boa prática fornecer exemplos que as pessoas possam compilar tal como estão, para reproduzir exatamente o comportamento errôneo. Ser capaz de reproduzir comportamento errôneo é importante para poder depurar o código que produz esse comportamento errôneo.


Dr. Nicola TalbotCriando um exemplo mínimo de LaTeXfornece algumas diretrizes.

Também háComo fazer um “exemplo mínimo”de texfaq.org, que também contém alguns links para conselhos para fazer perguntas.

EmO que é um exemplo mínimo de trabalho?Christian Faulhammer não usa o termo "Exemplo Mínimo", mas usa o termo "Exemplo Mínimo de Trabalho" mesmo para exemplos que funcionam apenas no sentido de que são suficientes para exibir um comportamento errôneo.

Você também pode estar interessado nas respostas à perguntaAcabei de ser solicitado a escrever um exemplo mínimo, o que é isso?

Responder2

O OP me pediu uma pequena explicação para esta resposta, então adicionarei algum texto aqui. O mecanismo padrão do LaTeX para argumentos opcionais permite um argumento opcional que vem antes dos argumentos obrigatórios. Assim, para criar uma sintaxe que forneça um argumento opcional, 2 argumentos obrigatórios e, em seguida, 2 argumentos opcionais, é necessário que 3 macros sejam encadeadas sucessivamente, uma vez que existem 3 argumentos opcionais solicitados.

A primeira macro absorve um argumento opcional mais 2 argumentos obrigatórios e então deve invocar uma segunda macro, e aqui está a chave,como sua ação final! A razão pela qual a segunda invocação da macro deve ser a ação final da primeira macro é que a segunda macro deve absorver um argumento opcional. Se houver algum token na primeira macro que segue a invocação da 2ª macro na cadeia, então esses outros tokens na 1ª macro serão absorvidos como argumento, em vez do pretendido.

Da mesma forma, a 2ª macro deve invocar a 3ª macro como ação final.

Certos destaques peculiares:

  1. se a macro sucessiva for chamada dentro de um \ifbloco, deve-se \expandafterantes da macro sucessiva, para que a macro sucessiva não tente absorver o \elseou \fi.

  2. Neste caso específico, o argumento opcional final, o rótulo, só pode ser chamado se uma legenda tiver sido especificada. Assim, a 2ª macro da cadeia só chamará a 3ª macro se uma legenda tiver sido especificada. Caso contrário, truncará a sequência.

O MWE:

\documentclass{article}
\usepackage{graphicx}
\newcommand\addtofigtoks[1]{\expandafter\figtoks\expandafter
  {\the\figtoks#1}}
\newtoks\figtoks
\newcommand\figCapLab[3][htbp]{%
  \figtoks{\begin{figure}[#1]}
  \addtofigtoks{\centering}
  \addtofigtoks{\includegraphics[width=#2\textwidth]{#3}}
  \optcap
}
\newcommand\optcap[1][\relax]{%
  \ifx\relax#1\relax
    \addtofigtoks{\end{figure}}
    \the\figtoks
  \else
    \addtofigtoks{\caption{#1}}%
    \expandafter\labelopt
  \fi
}
\newcommand\labelopt[1][\relax]{%
  \ifx\relax#1\relax\else\addtofigtoks{\label{#1}}\fi
  \addtofigtoks{\end{figure}}
  \the\figtoks
}
\begin{document}
\figCapLab{.2}{example-image-a}
\figCapLab{.2}{example-image-b}[My caption]
\figCapLab{.2}{example-image-c}[My caption][fg:label1]
\figCapLab[p]{.2}{example-image}[Other caption][fg:label2]

In figures \ref{fg:label1} and \ref{fg:label2}...
\end{document}

insira a descrição da imagem aqui

Ack-shu-ally, quanto mais penso nisso, os tokens nem são necessários:

\documentclass{article}
\usepackage{graphicx}
\newcommand\figCapLab[3][htbp]{%
  \begin{figure}[#1]
  \centering
  \includegraphics[width=#2\textwidth]{#3}
  \optcap
}
\newcommand\optcap[1][\relax]{%
  \ifx\relax#1\relax
    \end{figure}
  \else
    \caption{#1}%
    \expandafter\labelopt
  \fi
}
\newcommand\labelopt[1][\relax]{%
  \ifx\relax#1\relax\else\label{#1}\fi
  \end{figure}
}
\begin{document}
\figCapLab{.2}{example-image-a}
\figCapLab{.2}{example-image-b}[My caption]
\figCapLab{.2}{example-image-c}[My caption][fg:label1]
\figCapLab[p]{.2}{example-image}[Other caption][fg:label2]

In figures \ref{fg:label1} and \ref{fg:label2}...
\end{document}

Responder3

Veja como você pode atingir seu objetivo usandoxparse:

insira a descrição da imagem aqui

\documentclass{article}

\usepackage{graphicx,xparse}

% \figCapLab
%   [<float spec>]   #1
%   {<width factor>} #2
%   {<image>}        #3
%   [<caption>]      #4
%   [<label>]        #5
\NewDocumentCommand{\figCapLab}{ O{htbp} m m o o }{%
  \begin{figure}[#1]
    \centering
    \includegraphics[width=#2\linewidth]{#3}% Set image at width
    \IfValueT{#4}
      {\caption{#4}\IfValueT{#5}{\label{#5}}}% Set possible \caption and \label
  \end{figure}
}

\begin{document}

\figCapLab{.2}{example-image-a}
\figCapLab{.2}{example-image-b}[My caption]
\figCapLab{.2}{example-image-c}[My caption][fg:label1]
\figCapLab[p]{.2}{example-image}[Other caption][fg:label2]

In figures \ref{fg:label1} and \ref{fg:label2}\ldots

\end{document}

Argumentos opcionais com padrão são especificados usando O{<default>}while argumentos opcionais sem padrão usam o. O condicionamento sobre se um valor é fornecido ou não é feito usando \IfValueTF{<parameter>}{<true>}{<false>}. Existem também condicionais singulares \IfValueTe \IfValueF, o primeiro dos quais foi usado acima.

O código acima assume que uma legenda vazia (quarto argumento em branco) não precisaria de um \label(quinto) argumento. Se for necessário, mova o \IfValueT{#5}{\label{#5}}out do <true>branch para dentro \IfValueT{#4}:

\NewDocumentCommand{\figCapLab}{ O{htbp} m m o o }{%
  \begin{figure}[#1]
    \centering
    \includegraphics[width=#2\textwidth]{#3}% Set image at width
    \IfValueT{#4}{\caption{#4}}% Possible \caption
    \IfValueT{#5}{\label{#5}}% Possible \label
  \end{figure}
}

informação relacionada