
我有數百個文件名包含“#”的圖形,包括使用\includegraphics
,我嘗試過類似grffile
或 的包currfile
,但它們都不起作用。誰能提出一個真正的解決方案,這樣我就不需要更改數百個檔案名稱?謝謝。
更新: 1.我使用的是Windows。 2.編譯時顯示“定義中的參數號碼非法”
答案1
#
您可以在使用前更改catcode :
\documentclass[]{article}
\usepackage{graphicx}
\begin{document}
{\catcode`\#=12 \includegraphics{test#abc}}
\end{document}
但最好避免使用此類名稱。
答案2
catcode 更改的替代方案,這在巨集內部可能很棘手:
\documentclass{article}
\usepackage{graphicx}
\begin{document}
\includegraphics{a\string##b.png}
\end{document}
答案3
可以變更類別代碼,請參閱回答烏爾麗克·費雪。或者哈希可以隱藏在巨集中:
\edef\hash{\string#}
\hash
被定義為宏,它擴展為帶有數字等字元的類別代碼(12/其他)的雜湊。
例子:
\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}
答案4
該問題是由於圖形/graphicx-package 的檔案名稱處理/解析造成的:
作為參數提供的檔案名稱\includegraphics
被傳遞到臨時巨集的定義文字中。
當這些臨時巨集擴展時,連續散列的數量將減半,並且將採用單一雜湊作為標記,這些標記應位於 1..9 範圍內的數字之前用於表示參數。
\toks@{..}...\edef..{..\the\toks@..}
這可能可以通過或解決\edef...{\unexpanded{..}..}
。
如果\detokenize
eTeX-extensions 的 -primitive 可用,則可以實現檢查標記是否為類別代碼 6(參數)的明確字元標記。
因此,如果\detokenize
eTeX 擴展的原語可用,則可以實現透過其字串化/透過其類別代碼 12 掛件遞歸替換檔案名稱中的每個雜湊(類別代碼 6 的每個明確字元標記)的例程:
% 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}
但僅僅替換哈希並不是最好的解決方案。原因:除了雜湊值之外,檔案名稱還可能包含不平衡的花括號等。因此,從 .tex-input-file 讀取並在 verbatim-category-code-régime 下標記巨集參數的例程可能會很方便。
\UDcollectverbarg
我可以提供具有以下語法的巨集:
\UDcollectverbarg{⟨^^M-replacement⟩}{⟨mandatory 1⟩}{⟨mandatory 2⟩}⟨verbatimized argument⟩
產生:
⟨mandatory 1⟩{⟨mandatory 2⟩{⟨verbatim argument⟩}}
^^M
,表示行尾的每個字元都被標記序列取代⟨^^M-replacement⟩
。
參數⟨mandatory 1⟩
和⟨mandatory 2⟩
是強制性的。如果它們由多個標記組成,則這些標記必須嵌套在 catcode-1/2-explicit-character-token-pair 中/大括號中。
如果需要讀取和標記化,這將在未更改的類別代碼制度下進行。
這⟨verbatim argument⟩
也是強制性的。它將在逐字類別代碼制度下被讀取和標記化。如果它的第一個字元是大括號,則將「假定」參數嵌套在大括號中。否則,將假定該參數的結尾由第一個字元分隔,就像 的參數一樣\verb
。
空行不會被忽略。
我選擇這種語法是因為使用這種語法,您可以⟨mandatory 2⟩
透過巢狀呼叫來\UDcollectverbarg
收集逐字參數⟨mandatory 1⟩
。
例如,
\UDcollectverbarg{<^^M-replacement>}%
{\UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{<actionA>}}}% <- mandatory 1
{<actionB>}% <- mandatory 2
<verbatim argument 1><verbatim argument 2><verbatim argument 3>
產量:
\UDcollectverbarg{<^^M-replacement>}{\UDcollectverbarg{<^^M-replacement>}{<actionA>}}% <- mandatory 1
{<actionB>{<verbatimd argument 1>}}% <- mandatory 2
<verbatim argument 2><verbatim argument 3>
產量:
\UDcollectverbarg{<^^M-replacement>}{<actionA>}% <- mandatory 1
{<actionB>{<verbatim argument 1>}{<verbatim argument 2>}}% <- mandatory 2
<verbatim argument 3>
產量:
<actionA>{<actionB>{<verbatim argument 1>}{<verbatim argument 2>}{<verbatim argument 3>}}
假設<actionA>
= \@firstofone
:
\@firstofone{<actionB>{<verbatim argument 1>}{<verbatim argument 2>}{<verbatim argument 3>}}
產量:
<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}