
Ich habe Hunderte von Abbildungen mit Dateinamen, die "#" enthalten, die ich mit einbinden möchte. Ich habe Pakete wie oder \includegraphics
ausprobiert , aber keines davon funktioniert. Kann mir jemand eine echte Lösung vorschlagen, sodass ich nicht Hunderte von Dateinamen ändern muss? Danke.grffile
currfile
Update: 1. Ich verwende Windows. 2. Wenn ich es kompiliere, wird „Ungültige Parameternummer in der Definition“ angezeigt.
Antwort1
Sie können den Catcode #
vor der Verwendung ändern:
\documentclass[]{article}
\usepackage{graphicx}
\begin{document}
{\catcode`\#=12 \includegraphics{test#abc}}
\end{document}
Aber es ist wirklich besser, solche Namen zu vermeiden.
Antwort2
Eine Alternative zu Catcode-Änderungen, die in Makros schwierig sein können:
\documentclass{article}
\usepackage{graphicx}
\begin{document}
\includegraphics{a\string##b.png}
\end{document}
Antwort3
Entweder kann der Kategoriencode geändert werden, sieheAntwortvon Ulrike Fischer. Oder der Hash kann in einem Makro versteckt werden:
\edef\hash{\string#}
\hash
wird als Makro definiert, das zu einem Hash mit einem Kategoriencode (12/andere) eines zeichenähnlichen Zeichens erweitert wird.
Beispiel:
\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}
Antwort4
Das Problem liegt an der Dateinamenverarbeitung/-analyse des Grafik-/Graphicx-Pakets:
Der als Argument angegebene Dateiname \includegraphics
wird in die Definitionstexte temporärer Makros übergeben.
Wenn diese temporären Makros erweitert werden, wird die Anzahl der aufeinanderfolgenden Hashes halbiert und einzelne Hashes werden als Markierungen verwendet, die Ziffern im Bereich 1..9 zur Bezeichnung von Argumenten vorangehen sollten.
\toks@{..}...\edef..{..\the\toks@..}
Dies hätte wahrscheinlich über oder behoben werden können \edef...{\unexpanded{..}..}
.
Falls das \detokenize
-Primitiv der eTeX-Erweiterungen verfügbar ist, kann eine Überprüfung, ob ein Token ein explizites Zeichen-Token der Kategorie Code 6 (Parameter) ist, implementiert werden.
Falls also das \detokenize
-Primitiv der eTeX-Erweiterungen verfügbar ist, kann eine Routine zum rekursiven Ersetzen jedes Hashs (jedes expliziten Zeichentokens des Kategoriecodes 6) im Dateinamen durch seine Stringifizierung/durch sein Kategoriecode-12-Gegenstück implementiert werden:
% 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}
Aber nur Hashes zu ersetzen ist nicht die beste Lösung. Grund: Neben Hashes kann ein Dateiname auch ungleichmäßige geschweifte Klammern und dergleichen enthalten. Daher könnte eine Routine, die aus der .tex-Eingabedatei liest und Makroargumente unter dem Verbatim-Category-Code-Regime tokenisiert, praktisch sein.
\UDcollectverbarg
Ich kann ein Makro mit der folgenden Syntax anbieten :
\UDcollectverbarg{⟨^^M-replacement⟩}{⟨mandatory 1⟩}{⟨mandatory 2⟩}⟨verbatimized argument⟩
was ergibt:
⟨mandatory 1⟩{⟨mandatory 2⟩{⟨verbatim argument⟩}}
, wobei jedes Zeichen ^^M
, das ein Zeilenende anzeigt, durch die Token-Sequenz ersetzt wird ⟨^^M-replacement⟩
.
Die Argumente ⟨mandatory 1⟩
und ⟨mandatory 2⟩
sind obligatorisch. Wenn sie aus mehreren Token bestehen, müssen diese Token in einem Catcode-1/2-expliziten Zeichen-Token-Paar / in Klammern verschachtelt werden.
Wenn das Lesen und Tokenisieren erforderlich ist, erfolgt dies unter unverändertem Kategoriecode-Regime.
Das ⟨verbatim argument⟩
ist ebenfalls obligatorisch. Es ist unter wörtlichem Kategoriecode-Regime zu lesen und zu tokenisieren. Wenn sein erstes Zeichen eine Klammer ist, wird „angenommen“, dass das Argument in Klammern verschachtelt ist. Andernfalls wird angenommen, dass das Ende dieses Arguments durch dieses erste Zeichen begrenzt wird – wie das Argument von \verb
.
Leere Zeilen werden nicht ignoriert.
Ich habe diese Syntax gewählt, da Sie mit ihr wörtliche Argumente sammeln können, ⟨mandatory 2⟩
indem Sie Aufrufe \UDcollectverbarg
innerhalb verschachteln ⟨mandatory 1⟩
.
Z.B,
\UDcollectverbarg{<^^M-replacement>}%
{\UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{<actionA>}}}% <- mandatory 1
{<actionB>}% <- mandatory 2
<verbatim argument 1><verbatim argument 2><verbatim argument 3>
ergibt:
\UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{<actionA>}}% <- mandatory 1
{<actionB>{<verbatimd argument 1>}}% <- mandatory 2
<verbatim argument 2><verbatim argument 3>
ergibt:
\UDcollectverbarg{<^^M-replacement>}{<actionA>}% <- mandatory 1
{<actionB>{<verbatim argument 1>}{<verbatim argument 2>}}% <- mandatory 2
<verbatim argument 3>
ergibt:
<actionA>{<actionB>{<verbatim argument 1>}{<verbatim argument 2>}{<verbatim argument 3>}}
Angenommen <actionA>
= \@firstofone
:
\@firstofone{<actionB>{<verbatim argument 1>}{<verbatim argument 2>}{<verbatim argument 3>}}
ergibt:
<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}