\includegraphics: sinal numérico # no nome do arquivo

\includegraphics: sinal numérico # no nome do arquivo

Tenho centenas de figuras com nomes de arquivos contendo "#" para incluir usando \includegraphics, tentei pacotes como grffileou currfile, mas nenhum deles funciona. Alguém pode sugerir uma solução real para que eu não precise alterar centenas de nomes de arquivos? Obrigado.

Atualização: 1. Estou usando o Windows. 2. Quando compilo, aparece "Número de parâmetro ilegal na definição"

Responder1

Você pode alterar o catcode #antes de usá-lo:

\documentclass[]{article}
\usepackage{graphicx}


\begin{document}
{\catcode`\#=12 \includegraphics{test#abc}}
\end{document}

Mas é realmente melhor evitar esses nomes.

Responder2

Uma alternativa para alterações de catcode, que podem ser complicadas dentro de macros:

\documentclass{article}
\usepackage{graphicx}

\begin{document}

\includegraphics{a\string##b.png}

\end{document}

Responder3

O código da categoria pode ser alterado, consulte oresponderde Ulrike Fischer. Ou o hash pode estar oculto dentro de uma macro:

\edef\hash{\string#}

\hashé definido como uma macro que se expande para um hash com um código de categoria (12/outro) de um caractere como dígitos.

Exemplo:

\documentclass{article}
\usepackage{graphicx}
% \usepackage{grffile}

\newcommand*{\hash}{}% print error message if \hash is already defined
\edef\hash{\string#}

\begin{document}
  \includegraphics[width=.5\linewidth]{test\hash abc}% "test#abc"
\end{document}

Responder4

O problema é devido ao processamento/análise do nome do arquivo do pacote graphics/graphicx:

O nome do arquivo fornecido como argumento \includegraphicsé passado para os textos de definição das macros temporárias.

Quando essas macros temporárias forem expandidas, as quantidades de hashes consecutivos serão reduzidas à metade e hashes únicos serão usados ​​para marcadores que devem preceder os dígitos no intervalo 1..9 para denotar argumentos.

Isso provavelmente poderia ter sido resolvido via \toks@{..}...\edef..{..\the\toks@..}ou \edef...{\unexpanded{..}..}.

Caso o \detokenize-primitivo das extensões eTeX esteja disponível, pode ser implementada a verificação se um token é um token de caractere explícito do código de categoria 6 (parâmetro).

Assim, caso o \detokenize-primitivo das extensões eTeX esteja disponível, uma rotina para substituir recursivamente cada hash (cada token de caractere explícito do código de categoria 6) no nome do arquivo por sua stringificação/por seu código de categoria-12-pendente pode ser implementada :

% This example uses \detokenize and thus requires eTeX extensions.

\documentclass{article}
\usepackage{graphicx}

\makeatletter
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo,
%%    \UD@PassFirstToSecond, \UD@Exchange, \UD@removespace
%%    \UD@CheckWhetherNull, \UD@CheckWhetherBrace,
%%    \UD@CheckWhetherLeadingSpace, \UD@ExtractFirstArg
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% \UD@CheckWhetherBrace{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has leading
%%                        catcode-1-token>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has no leading
%%                        catcode-1-token>}%
\newcommand\UD@CheckWhetherBrace[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\expandafter{\expandafter{%
  \string#1.}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@firstoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a space-token
%%.............................................................................
%% \UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is a
%%                               space-token>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is not
%%                               a space-token>}%
\newcommand\UD@CheckWhetherLeadingSpace[1]{%
  \romannumeral0\UD@CheckWhetherNull{#1}%
  {\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
  {\expandafter\UD@secondoftwo\string{\UD@CheckWhetherLeadingSpaceB.#1 }{}}%
}%
\newcommand\UD@CheckWhetherLeadingSpaceB{}%
\long\def\UD@CheckWhetherLeadingSpaceB#1 {%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
  {\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
  {\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
   \expandafter\expandafter\expandafter}\expandafter\expandafter
   \expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%
%%   \UD@ExtractFirstArg{ABCDE} yields  {A}
%%
%%   \UD@ExtractFirstArg{{AB}CDE} yields  {AB}
%%.............................................................................
\newcommand\UD@RemoveTillUD@SelDOm{}%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
\newcommand\UD@ExtractFirstArg[1]{%
  \romannumeral0%
  \UD@ExtractFirstArgLoop{#1\UD@SelDOm}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  { #1}%
  {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%=============================================================================
%% \ReplaceEveryHash{<argument>}%
%%
%%   Each explicit catcode-6(parameter)-character-token of the <argument> 
%%   will be replaced by its stringification.
%%
%%   You obtain the result after two expansion-steps, i.e., 
%%   in expansion-contexts you get the result after "hitting" 
%%   \ReplaceEveryHash by two \expandafter.
%%   
%%   As a side-effect, the routine does replace matching pairs of explicit
%%   character tokens of catcode 1 and 2 by matching pairs of curly braces
%%   of catcode 1 and 2.
%%   I suppose this won't be a problem in most situations as usually the
%%   curly braces are the only characters of category code 1 / 2...
%%
%%   This routine needs \detokenize from the eTeX extensions.
%%-----------------------------------------------------------------------------
\newcommand\ReplaceEveryHash[1]{%
  \romannumeral0\UD@ReplaceEveryHashLoop{#1}{}%
}%
\newcommand\UD@ReplaceEveryHashLoop[2]{%
  \UD@CheckWhetherNull{#1}{ #2}{%
    \UD@CheckWhetherLeadingSpace{#1}{%
       \expandafter\UD@ReplaceEveryHashLoop
       \expandafter{\UD@removespace#1}{#2 }%
    }{%
      \UD@CheckWhetherBrace{#1}{%
        \expandafter\expandafter\expandafter\UD@PassFirstToSecond
        \expandafter\expandafter\expandafter{%
        \expandafter\UD@PassFirstToSecond\expandafter{%
            \romannumeral0\expandafter\UD@ReplaceEveryHashLoop
            \romannumeral0\UD@ExtractFirstArgLoop{#1\UD@SelDOm}{}%
        }{#2}}%
        {\expandafter\UD@ReplaceEveryHashLoop
         \expandafter{\UD@firstoftwo{}#1}}%
      }{%
       \expandafter\UD@CheckWhetherHash
       \romannumeral0\UD@ExtractFirstArgLoop{#1\UD@SelDOm}{#1}{#2}%
      }%
    }%
  }%
}%
\newcommand\UD@CheckWhetherHash[3]{%
  \expandafter\UD@CheckWhetherLeadingSpace\expandafter{\string#1}{%
    \expandafter\expandafter\expandafter\UD@CheckWhetherNull
    \expandafter\expandafter\expandafter{%
    \expandafter\UD@removespace\string#1}{%
      \expandafter\expandafter\expandafter\UD@CheckWhetherNull
      \expandafter\expandafter\expandafter{%
      \expandafter\UD@removespace\detokenize{#1}}{% Something whose stringification yields a single space
        \expandafter\UD@ReplaceEveryHashLoop
        \expandafter{\UD@firstoftwo{}#2}{#3#1}%
      }{% Explicit space of catcode 6
        \expandafter\expandafter\expandafter\UD@PassFirstToSecond
        \expandafter\expandafter\expandafter{\expandafter\UD@Exchange
        \expandafter{\string#1}{#3}}{%
          \expandafter\UD@ReplaceEveryHashLoop
          \expandafter{\UD@firstoftwo{}#2}%
        }%
      }%
    }{% Something whose stringification has a leading space
      \expandafter\UD@ReplaceEveryHashLoop
      \expandafter{\UD@firstoftwo{}#2}{#3#1}%
    }%
  }{%
    \expandafter\expandafter\expandafter\UD@CheckWhetherNull
    \expandafter\expandafter\expandafter{%
    \expandafter\UD@firstoftwo
    \expandafter{\expandafter}\string#1}{%
      \expandafter\expandafter\expandafter\UD@CheckWhetherNull
      \expandafter\expandafter\expandafter{%
      \expandafter\UD@firstoftwo
      \expandafter{\expandafter}\detokenize{#1}}{% No Hash
        \expandafter\UD@ReplaceEveryHashLoop
        \expandafter{\UD@firstoftwo{}#2}{#3#1}%
      }{% Hash
        \expandafter\expandafter\expandafter\UD@PassFirstToSecond
        \expandafter\expandafter\expandafter{\expandafter\UD@Exchange
        \expandafter{\string#1}{#3}}{%
          \expandafter\UD@ReplaceEveryHashLoop
          \expandafter{\UD@firstoftwo{}#2}%
        }%
      }%
    }{% No Hash
      \expandafter\UD@ReplaceEveryHashLoop
      \expandafter{\UD@firstoftwo{}#2}{#3#1}%
    }%
  }%
}%
%----------------------------------------------------------------------
\makeatother

\begin{document}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\mytempa
\expandafter\expandafter\expandafter{\ReplaceEveryHash{F#m.png}}

\includegraphics[width=5cm]{\mytempa}

\end{document}

Mas apenas substituir hashes não é a melhor solução. Motivo: além dos hashes, um nome de arquivo também pode conter chaves desequilibradas e similares. Portanto, uma rotina que lê o arquivo de entrada .tex e tokeniza argumentos de macro no regime de código de categoria literal pode ser útil.

Posso oferecer uma macro \UDcollectverbargcom a seguinte sintaxe:

\UDcollectverbarg{⟨^^M-replacement⟩}{⟨mandatory 1⟩}{⟨mandatory 2⟩}⟨verbatimized argument⟩

que produz:

⟨mandatory 1⟩{⟨mandatory 2⟩{⟨verbatim argument⟩}}

, com cada caractere ^^Mque denota o fim de uma linha sendo substituído pelo token-sequence ⟨^^M-replacement⟩.

Os argumentos ⟨mandatory 1⟩e ⟨mandatory 2⟩são obrigatórios. Se eles consistirem em vários tokens, esses tokens deverão ser aninhados em um catcode-1/2-explicit-character-token-pair / entre colchetes.
Se for necessária leitura e tokenização, isso ocorrerá sob regime de código de categoria inalterado.
O ⟨verbatim argument⟩também é obrigatório. Deve ser lido e tokenizado sob o regime de código de categoria literal. Se seu primeiro caractere for uma chave, será "assumido" que o argumento está aninhado entre chaves. Caso contrário, será assumido que o final desse argumento é delimitado pelo primeiro caractere - como o argumento de \verb.
Linhas vazias não serão ignoradas.

Eu escolhi esta sintaxe, pois com ela você pode coletar argumentos literais ⟨mandatory 2⟩aninhando chamadas para \UDcollectverbarginside ⟨mandatory 1⟩.

Por exemplo,

\UDcollectverbarg{<^^M-replacement>}%
                 {\UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{<actionA>}}}% <- mandatory 1
                 {<actionB>}%                     <- mandatory 2
                 <verbatim argument 1><verbatim argument 2><verbatim argument 3>

rendimentos:

\UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{<actionA>}}% <- mandatory 1
                 {<actionB>{<verbatimd argument 1>}}%        <- mandatory 2
                 <verbatim argument 2><verbatim argument 3>

rendimentos:

\UDcollectverbarg{<^^M-replacement>}{<actionA>}% <- mandatory 1
                 {<actionB>{<verbatim argument 1>}{<verbatim argument 2>}}% <- mandatory 2
                 <verbatim argument 3>

rendimentos:

<actionA>{<actionB>{<verbatim argument 1>}{<verbatim argument 2>}{<verbatim argument 3>}}

Suponha <actionA>= \@firstofone:

\@firstofone{<actionB>{<verbatim argument 1>}{<verbatim argument 2>}{<verbatim argument 3>}}

rendimentos:

<actionB>{<verbatim argument 1>}{<verbatim argument 2>}{<verbatim argument 3>}

% This example does not require eTeX extensions.

\errorcontextlines=10000

\makeatletter
%%<-------------------- Code for \UDcollectverbarg -------------------->
%% Copyright (C) 2007 - 2019 by Ulrich Diez ([email protected])
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public Licence (LPPL), either
%% version 1.3 of this license or (at your option) any later
%% version. (The latest version of this license is in:
%% http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status 'not maintained'.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty - neither for probably included
%% documentation nor for any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%
\newcommand\UD@firstofone[1]{#1}%
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
%%
%% Check whether argument is empty:
%%......................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%......................................................................
\begingroup
\catcode`\^^M=12 %
\UD@firstofone{%
  \endgroup%
  \newcommand\UDEndlreplace[2]{\romannumeral0\@UDEndlreplace{#2}#1^^M\relax{}}%
  \newcommand*\@UDEndlreplace{}%
  \long\def\@UDEndlreplace#1#2^^M#3\relax#4#5{%
    \UD@CheckWhetherNull{#3}%
    { #5{#4#2}}{\@UDEndlreplace{#1}#3\relax{#4#2#1}{#5}}%
  }%
}%
\newcommand\UDcollectverbarg[3]{%
  \begingroup
  \let\do\@makeother % <- this and the next line switch to
  \dospecials        %    verbatim-category-code-régime.
  \catcode`\{=1      % <- give opening curly brace the usual catcode so a 
                     %    curly-brace-balanced argument can be gathered in
                     %    case of the first thing of the verbatimized-argument 
                     %    being a curly opening brace.
  \catcode`\ =10     % <- give space and horizontal tab the usual catcode so \UD@collectverbarg
  \catcode`\^^I=10   %    cannot catch a space or a horizontal tab as its 4th undelimited argument.
                     %    (Its 4th undelimited argument denotes the verbatim-
                     %     syntax-delimiter in case of not gathering a
                     %     curly-brace-nested argument.)
  \kernel@ifnextchar\bgroup
  {% seems a curly-brace-nested argument is to be caught:
    \catcode`\}=2    % <- give closing curly brace the usual catcode also.
    \UD@collectverbarg{#1}{#2}{#3}{}%
  }{% seems an argument with verbatim-syntax-delimiter is to be caught:
    \do\{% <- give opening curly brace the verbatim-catcode again.
    \UD@collectverbarg{#1}{#2}{#3}%
  }%
}%
\newcommand\UD@collectverbarg[4]{%
  \do\ %   <- Now that \UD@collectverbarg has the delimiter or
  \do\^^I%    emptiness in its 4th arg, give space and horizontal tab
         %    the verbatim-catcode again.
  \do\^^M% <- Give the carriage-return-character the verbatim-catcode.
  \long\def\@tempb##1#4{%
    %\edef\@tempb{##1}%
    \def\@tempb{##1}%
    \@onelevel@sanitize\@tempb % <- Turn characters into their "12/other"-pendants.
                               %    This may be important with things like the 
                               %    inputenc-package which may make characters 
                               %    active/which give them catcode 13(active).
    \expandafter\UDEndlreplace\expandafter{\@tempb}{#1}{\def\@tempb}% <- this starts 
                               %    the loop for replacing endline-characters.
    \expandafter\UD@@collectverbarg\expandafter{\@tempb}{#2}{#3}% <- this "spits 
                               %    out the result.
  }%
  \@tempb
}%
\newcommand\UD@@collectverbarg[3]{%
  \endgroup
  #2{#3{#1}}%
}%
%%<---------------- End of code for \UDcollectverbarg ----------------->
\makeatother

\documentclass{article}
\usepackage{graphicx}

\begin{document}

\begingroup\catcode`\^^M=12\relax%
\UDcollectverbarg{^^M}{\endgroup\csname @firstofone\endcsname}{\def\mytempa}|F#m.png|%

\includegraphics[width=5cm]{\mytempa}

\end{document}

informação relacionada