
再會,
我正在嘗試找到一種有效的方法來存取遠端資料夾中的文件。我已經為路徑定義了幾個命令。
以下程式碼的第 6 行有效並包含正確的文件,而第 8 行則聲明「未找到文件」—但這兩個路徑不應該完全相同嗎?我不允許像這樣連接命令嗎?
1 \newcommand{\results}{../../code/data/results/}
2 \newcommand{\synthetic}{\results synthetic/}
3 \newcommand{\sine}[1]{sine_#1hz.pdf}
4
5
6 \includegraphics[width=.3\linewidth]{\synthetic sine_100hz.pdf}
7
8 \includegraphics[width=.3\linewidth]{\synthetic \sine{100}}
也許我沒有看到明顯的東西。這是我第一次在命令中使用路徑名。有人知道我錯過了什麼?
乾杯
編輯:這是一個完整的程式碼範例:
\documentclass[]{article}
\usepackage{graphicx}
\begin{document}
\newcommand{\results}{../../code/waveletTest/data/results/}
\newcommand{\synthetic}{\results synthetic/}
\newcommand{\sine}[1]{sine_#1hz.pdf}
\includegraphics[width=.3\linewidth]{\synthetic sine_100hz.pdf}
%\includegraphics[width=.3\linewidth]{\synthetic \sine{100}}
\end{document}
這段程式碼顯示了我想要的檔案。如果我在倒數第二行中進行評論,則會收到此錯誤:
File `../../code/waveletTest/data/results/synthetic/sine_100hz.pdf' not found. ...width=.3\linewidth]{\synthetic \sine{100}}
答案1
在我的系統上,在處理您的\includegraphics
命令的某個階段,您會得到以下序列:
\filename@parse{\synthetic\sine{100}}
\filename@parse
是 LaTeX 2ε-kernel 的一個例程,它將其參數分為
- 文件路徑。文件的路徑將儲存在巨集中
\filename@area
。 - 檔案名稱(不含副檔名)。檔案名稱(不含副檔名)將儲存在
\filename@base
. - 檔案名稱的副檔名。檔案名稱的副檔名將儲存在
\filename@ext
.如果沒有副檔名,\filename@ext
則令等於\relax
。
會發生什麼事:
在我的系統上\filename@parse
,文法: 定義如下:
\filename@parse{⟨file-path/filename-specification⟩}
> \filename@parse=macro:
#1->\let \filename@area \@empty \expandafter \filename@path #1/\\
因此\filename@parse
初始化\filename@area
為等於宏\empty
- 宏\empty
在其頂級擴展期間從令牌流中消失,不處理任何參數,並提供一個空的/根本不包含任何令牌的替換文字 - 並調用\filename@path
「擊中」參數的第一個標記後的例程\expandafter
一次並附加到/\\
結果。 (如果參數#1
為空,則附加的斜線/
將被擊中,\expandafter
這不會有害,因為明確斜線字元令牌(catcode 12(其他))不可擴展。)
\filename@path
稍後將解釋該例程。目前僅此而已:\filename@path
縮排處理一系列不可擴展的顯式字元標記形成檔案路徑/檔案名稱規範 ( #1
),後面跟著類別代碼 12(其他)的明確斜線字元標記和作為檔案路徑/檔案名稱末尾的分隔符號/標記的/
控制符號標記\\
因此,如果提供檔案路徑/檔案名稱規範的參數不包含一系列不可擴展的明確字元標記,而是由其頂層的巨集標記形成,則\expandafter
一次」是透過以下方式完成的:「點擊\filename@parse
這種「擊中\expandafter
一次」意味著,對於\includegraphics
內部使用的諸如 之類的東西\filename@parse
,您只能根據標記序列提供文件路徑/文件名規範,其中擊中序列的第一個標記\expandafter
一次就足以獲取整個序列形成文件路徑/文件名規範的不可擴展的明確字元標記。
\expandafter
請注意,在您的場景中,序列的第一個標記上的單一「點擊」\synthetic \sine{100}
不會根據不可擴展的顯式字元標記序列產生整個(完全擴展的)檔案路徑/檔案名稱規範,但會產生\results synthetic/\sine{100}
需要完成更多擴展工作的順序。
\filename@path
因此,其底層程式無法正確完成元件的分割/拼接(檔案路徑、不含副檔名的檔案名稱、檔案副檔名) 。
反過來,該例程\filename@path
「期望」以一系列不可擴展的顯式字元標記的形式提供檔案路徑/檔案名稱規範,語法: ;是資料夾/目錄分隔符 ,定義如下:
\filename@path ⟨file-path/filename-specification in terms of a sequence of non-expandable explicit character-tokens⟩/\\
/
> \filename@path=macro:
#1/#2\\->\ifx \\#2\\\def \reserved@a {\filename@simple #1.\\}\else \edef \filen
ame@area {\filename@area #1/}\def \reserved@a {\filename@path #2\\}\fi \reserve
d@a
\filename@path
/
是一個遞歸循環,在每次迭代中將檔案路徑/檔案名稱規範的下一個分隔段附加到宏\filename@area
,直到到達表示檔案名稱的最後一個這樣的段。下一個(也可能是最後一個)部分位於#1
.下一個段之後的段位於 中#2
。因此,最後一段的指標是 的空#2
。
空性的測試#2
是: 當到達最後一個表示檔名的段時,呼叫巨集來檢查最後一個段/檔名是否包含點(
\ifx\\#2\\⟨tokens in case #2 is empty⟩\else⟨tokens in case #2 is not empty⟩\fi
\filename@simple
.
),因此需要從檔案名稱中剪接出檔案副檔名。如果需要拼接檔案副檔名,可以透過巨集來完成\filename@dot
。
當呼叫 時\filename@simple
,語法:在 最後一個表示檔案名稱的分隔段上,序列將附加到最後一個段落。 因此可以收集點分隔參數和- 分隔參數,並根據是否為空來檢測段中存在的點或附加點是否被用作點分隔參數的分隔符號。
\filename@simple ⟨filename-specification in terms of a sequence of non-expandable explicit character-tokens⟩.\\
/
.\\
\filename@simple
#1
\\
#2
#2
\filename@simple
定義如下:
> \filename@simple=macro:
#1.#2\\->\ifx \\#2\\\let \filename@ext \relax \else \edef \filename@ext {\filen
ame@dot #2\\}\fi \edef \filename@base {#1}
如果最後一個段落/檔案名稱不包含點,則將採用.
附加序列中的 來.\\
作為分隔符,#1
而\\
-delimited#2
將為空。否則,將採用最後一段的第一個點作為分隔符,#1
而\\
-delimited#2
不會為空。因此, #2
( ...)的空值\ifx\\#2\\
被視為最後一段是否形成沒有(點分隔)副檔名的檔案名稱或形成由點與檔案副檔名分隔的檔案名稱的指示符號。如果#2
為空,則\filename@ext
「\let
」等於\relax
。否則,在定義\filename@ext
via時\edef
,\filename@dot
將應用於第一個點後面的內容,以刪除附加的序列.\\
。無論如何,\filename@base
定義為擴展到第一個點之前的內容。
\filename@dot
定義如下:
> \filename@dot=macro:
#1.\\->#1
這\filename@parse
機制很好。但它有一些限制。
例如,假設檔名最多包含一個點。
例如,假設檔案名稱最多包含一個點,該點將檔案名稱(不含副檔名)與檔案副檔名分開,而檔案副檔名又不為空。以點結尾的檔案名稱(在某些檔案系統上完全「合法」)可能會造成麻煩。
例如,不考慮具有特殊類別代碼的特殊字元。例如,對於包含大括號的檔案路徑/檔案名稱規範,大括號可能不平衡或可能被剝離和/或可能「掩蓋」點和斜線被用作定界參數的定界符。這樣的事情會帶來麻煩。例如,包含雜湊值的檔案路徑/檔案名稱規範在定義臨時巨集時可能會導致問題,例如\reserved@a
儲存分割檔案路徑/檔案名稱規範的結果的巨集)時可能會導致問題。
例如,假設\expandafter
/ 在參數的第一個標記上觸發單個擴展步驟(→這就是術語“頂級擴展”的含義)的單個“命中”\filename@parse
足以獲取整個文件路徑/文件名規範以不可擴展的顯式字符標記序列表示。在您的情況下,情況並非如此,因此在\sine
尚未擴展時會嘗試進行拆分,因此該\filename@simple
機制還無法「看到」將檔案名稱(不含副檔名)與檔案副檔名分開的點。因此,在您的場景中,graphicx-package 錯誤地「假設」未指定檔案副檔名。如果graphicx-package「假設」(假設正確或錯誤)未指定檔案副檔名,它會嘗試使用一些預設副檔名。
例如,改為../../code/waveletTest/data/results/synthetic/sine_100hz.pdf
嘗試使用
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf.pdf
、
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf.png
、 等
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf.jpg
。
這就是為什麼輸入“H⟨返回⟩" 當控制台/螢幕上彈出錯誤訊息時,會產生:
I could not locate the file with any of these extensions:
.pdf,.png,.jpg,.mps,.jpeg,.jbig2,.jb2,.PDF,.PNG,.JPG,.JPEG,.JBIG2,.JB2,.eps
Try typing <return> to proceed.
If that doesn't work, type X <return> to quit.
David Carlisle(graphicx-package 的編寫者)提出的省略檔案副檔名的建議.pdf
旨在這樣一個事實:儘管在這種情況下,在檢查檔案副檔名是否存在之前擴展內容仍然不會以以下方式進行:會滿足純粹的想法,graphicx-package沒有指定檔案副檔名的假設是正確的,因此graphicx-package確實以一種可行的方式嘗試預設副檔名-graphicx-package嘗試 使用等第 一個已經解決了,
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf
,
../../code/waveletTest/data/results/synthetic/sine_100hz.png
../../code/waveletTest/data/results/synthetic/sine_100hz.jpg
所有這些事情都可以透過載入套件來解決grf文件:
\documentclass[]{article}
\usepackage{graphicx}
\usepackage{grffile}
\begin{document}
\newcommand{\results}{../../code/waveletTest/data/results/}
\newcommand{\synthetic}{\results synthetic/}
\newcommand{\sine}[1]{sine_#1hz.pdf}
%\includegraphics[width=.3\linewidth]{\synthetic sine_100hz.pdf}
\includegraphics[width=.3\linewidth]{\synthetic\sine{100}}
\end{document}
順便一提:
在您非常特殊的情況下,您可以\filename@parse
透過添加以下內容來欺騙 - 機制正確拼接檔案副檔名\expandafter
:
\documentclass[]{article}
\usepackage{graphicx}
\begin{document}
\newcommand{\results}{../../code/waveletTest/data/results/}
\newcommand{\synthetic}{\results synthetic/}
\newcommand{\sine}[1]{sine_#1hz.pdf}
%\includegraphics[width=.3\linewidth]{\synthetic sine_100hz.pdf}
\includegraphics[width=.3\linewidth]{\expandafter\synthetic\sine{100}}
\end{document}
至少在我的系統上這是可行的。
請注意,這確實正確地拼接了檔案副檔名但這並不能正確地將檔案路徑與檔案名稱分開。
文件路徑將被視為空。
該序列\synthetic sine_100hz
將被用作檔案名稱。
看來這並不重要。
但是\filename@parse
是 LaTeX 2ε 核心的巨集。最近,LaTeX 2ε 核心發生了許多變化和創新。可能\filename@parse
您的系統上的效果與我的系統上的效果不同。
我假設“一次點擊參數的第一個標記,\expandafter
以從巨集的頂級擴展中獲取以不可擴展的顯式字元標記表示的文件路徑/文件名規範”將不會從\filename@parse
。
因此,您可以應用一些\romannumeral
擴充技巧,它需要一次點擊來\expandafter
傳遞檔案路徑/檔案名稱規格:
\documentclass[]{article}
\usepackage{graphicx}
\begin{document}
\newcommand{\results}{../../code/waveletTest/data/results/}
\newcommand{\synthetic}{\results synthetic/}
\newcommand{\sine}[1]{sine_#1hz.pdf}
%\includegraphics[width=.3\linewidth]{\synthetic sine_100hz.pdf}
\includegraphics[width=.3\linewidth]{\romannumeral0\expandafter\synthetic\sine{100}}
\end{document}
這裡發生了什麼事?
\filename@parse
確實\expandafer
「擊中」了\romannumeral
。
然後\romannumeral
-觸發TeX的收集-⟨數字⟩-數量正在進行中:
%\romannumeral-triggered gathering of a TeX-number-quantity is in progress:
0\expandafter\synthetic\sine{100}
現在 LaTeX 找到該數字0
並將其丟棄。
現在收集 TeX 的過程-⟨數字⟩-數量轉變為收集更多數字的過程或終止收集 TeX 的過程-⟨數字⟩-數量:
%\romannumeral-triggered gathering of more digits is in progress; digit "0" found.
\expandafter\synthetic\sine{100}
現在 LaTeX 擴充了\expandafter
.展開的結果\expandafter
是展開\sine
:
%\romannumeral-triggered gathering of more digits is in progress; digit "0" found.
\synthetic sine_100hz.pdf
現在 LaTeX 擴充了\synthetic
.
%\romannumeral-triggered gathering of more digits is in progress; digit "0" found.
\results synthetic/sine_100hz.pdf
現在 LaTeX 擴充了\results
.
%\romannumeral-triggered gathering of more digits is in progress; digit "0" found.
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf
現在 LaTeX 找到了一個點。那個點不是數字。與空間令牌不同,它不會被丟棄。就像空間令牌一樣,它確實結束\romannumeral
- 觸發 TeX(的組件)的收集 -⟨數字⟩-數量。因此 LaTeX 只找到數字/數字,0
而 0 不是正數。對於非正數,\romannumeral
完全不回傳任何標記:
%\romannumeral done.
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf