Guten Tag,
Ich versuche, eine effiziente Methode zu finden, um auf Dateien in einem Remote-Ordner zuzugreifen. Ich habe mehrere Befehle für die Pfade definiert.
Zeile 6 des folgenden Codes funktioniert und enthält die richtige Datei, während Zeile 8 „Datei nicht gefunden“ anzeigt – aber sollten diese beiden Pfade nicht genau gleich sein? Darf ich Befehle nicht auf diese Weise verketten?
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}}
Vielleicht übersehe ich etwas Offensichtliches. Dies ist das erste Mal, dass ich mit Pfadnamen in Befehlen arbeite. Weiß jemand, was ich übersehe?
Prost
BEARBEITEN: Dies ist ein vollständiges Codebeispiel:
\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}
Dieser Code zeigt mir die gewünschte Datei. Wenn ich in der vorletzten Zeile zurückkommentiere, erhalte ich diesen Fehler:
File `../../code/waveletTest/data/results/synthetic/sine_100hz.pdf' not found. ...width=.3\linewidth]{\synthetic \sine{100}}
Antwort1
Auf meinem System \includegraphics
erhalten Sie an einem bestimmten Punkt der Verarbeitung Ihres -Befehls die Sequenz:
\filename@parse{\synthetic\sine{100}}
\filename@parse
ist eine Routine des LaTeX 2ε-Kernels, die ihr Argument aufspaltet in
- Pfad zur Datei. Der Pfad zur Datei soll im Makro hinterlegt werden
\filename@area
. - Name der Datei (ohne Erweiterung). Der Name der Datei (ohne Erweiterung) soll in gespeichert werden
\filename@base
. - Erweiterung des Dateinamens. Die Erweiterung des Dateinamens soll in gespeichert werden
\filename@ext
. Falls keine Erweiterung vorhanden ist,\filename@ext
wird gleich gesetzt\relax
.
Was passiert:
Auf meinem System ist \filename@parse
die Syntax wie folgt definiert:
\filename@parse{⟨file-path/filename-specification⟩}
> \filename@parse=macro:
#1->\let \filename@area \@empty \expandafter \filename@path #1/\\
\filename@parse
Initialisiert also \filename@area
gleich dem Makro \empty
—das Makro \empty
verschwindet einfach während seiner Toplevel-Expansion aus dem Token-Stream, ohne ein Argument zu verarbeiten und liefert einen Ersatztext, der leer ist bzw. der überhaupt kein Token enthält—und ruft die Routine auf, \filename@path
nachdem das erste Token des Arguments mit\expandafter
einmalund /\\
an das Ergebnis anhängen. (Falls das Argument leer ist, wird #1
der angehängte Schrägstrich mit angegeben , was jedoch nicht schädlich ist, da das explizite Schrägstrich-Zeichen-Token (von Catcode 12(other)) nicht erweiterbar ist.)/
\expandafter
Die Routine \filename@path
wird kurz erklärt. An dieser Stelle nur so viel:\filename@path
ist eingerückt, um eine Folge nicht erweiterbarer expliziter Zeichen-Tokens zu verarbeitendas eine Dateipfad-/Dateinamenspezifikation ( #1
) bildet, gefolgt von einem expliziten Schrägstrich-Zeichen-Token /
des Kategoriecodes 12 (andere) und einem Steuersymbol-Token \\
als Trennzeichen/Markierung für das Ende der Dateipfad-/Dateinamenspezifikation.
Das "Treffer-mit- \expandafter
Einmal"-Verfahren wird daher \filename@parse
dann angewendet, wenn das Argument zur Bereitstellung der Dateipfad-/Dateinamenspezifikation nicht aus einer Folge nicht erweiterbarer expliziter Zeichen-Token besteht, sondern aus einem Makro-Token besteht, dessen Erweiterung auf oberster Ebene eine Folge nicht erweiterbarer expliziter Zeichen-Token ergibt.
Dieses „einmalige Treffen \expandafter
“ impliziert, dass Sie bei Dingen wie \includegraphics
, die intern verwenden \filename@parse
, Dateipfad-/Dateinamenspezifikationen nur in Form von Tokensequenzen angeben können, bei denen das \expandafter
einmalige Treffen des ersten Tokens der Sequenz ausreicht, um die gesamte Sequenz nicht erweiterbarer expliziter Zeichen-Token zu erhalten, die die Dateipfad-/Dateinamenspezifikation bilden.
Beachten Sie, dass in Ihrem Szenario ein einzelner „Treffer mit \expandafter
“ auf dem ersten Token der Sequenz \synthetic \sine{100}
nicht die gesamte (vollständig erweiterte) Dateipfad-/Dateinamenspezifikation in Form einer Sequenz nicht erweiterbarer expliziter Zeichen-Token ergibt, sondern die Sequenz, \results synthetic/\sine{100}
in der weitere Erweiterungsarbeit erforderlich ist.
Daher wird das Aufteilen/Abtrennen der Komponenten (Pfad zur Datei, Name der Datei ohne Erweiterung, Dateinamenerweiterung) von \filename@path
den zugrunde liegenden Routinen nicht korrekt durchgeführt.
Die Routine \filename@path
wiederum, die „erwartet“, dass die Dateipfad-/Dateinamenspezifikation in Form einer Folge nicht erweiterbarer expliziter Zeichen-Tokens bereitgestellt wird, mit der Syntax: ; ist Ordner-/Verzeichnistrennzeichen , ist wie folgt definiert:
\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
ist eine rekursive Schleife, die in jeder Iteration das nächste /
durch - begrenzte Segment des Dateipfads/der Dateinamensspezifikation an das Makro anhängt \filename@area
, bis das letzte derartige Segment erreicht ist, das den Dateinamen bezeichnet. Dieses nächste (und wahrscheinlich letzte) Segment befindet sich in #1
. Die Segmente, die diesem nächsten Segment folgen, befinden sich in #2
. Der Indikator für das letzte Segment ist also die Leere von #2
.
Der Test auf Leere von #2
lautet: Beim Erreichen des letzten derartigen Segments, das den Dateinamen bezeichnet, wird das Makro aufgerufen, um zu prüfen, ob dieses letzte Segment/der letzte Dateiname einen Punkt ( ) enthält und deshalb eine Dateinamenerweiterung vom Dateinamen abgetrennt werden muss. Wenn eine Dateinamenerweiterung abgetrennt werden muss, geschieht dies mithilfe des Makros .
\ifx\\#2\\⟨tokens in case #2 is empty⟩\else⟨tokens in case #2 is not empty⟩\fi
\filename@simple
.
\filename@dot
Beim Aufruf von \filename@simple
, Syntax: , auf das letzte -getrennte Segment, das den Dateinamen bezeichnet, wird die Sequenz an das letzte Segment angehängt. So lässt sich ein punktgetrenntes Argument und ein -getrenntes Argument erfassen und je nach Leere erkennen, ob ein im Segment vorhandener Punkt oder der angehängte Punkt als Trennzeichen des punktgetrennten Arguments verwendet wurde.
\filename@simple ⟨filename-specification in terms of a sequence of non-expandable explicit character-tokens⟩.\\
/
.\\
\filename@simple
#1
\\
#2
#2
\filename@simple
wird wie folgt definiert:
> \filename@simple=macro:
#1.#2\\->\ifx \\#2\\\let \filename@ext \relax \else \edef \filename@ext {\filen
ame@dot #2\\}\fi \edef \filename@base {#1}
Falls das letzte Segment/der letzte Dateiname keinen Punkt enthielt, wird .
aus der angehängten Sequenz als Trennzeichen von verwendet, während das durch - getrennte leer ist. Andernfalls wird der erste Punkt des letzten Segments als Trennzeichen von verwendet, während das durch - getrennte nicht leer ist. Somit wird die Leere von ( ...) als Indikator dafür verwendet, ob das letzte Segment einen Dateinamen ohne (durch Punkte getrennte) Erweiterung bildet oder einen Dateinamen, der durch einen Punkt von der Dateierweiterung getrennt ist. Wenn leer ist, ist " " gleich . Andernfalls wird beim Definieren über auf die Dinge hinter dem ersten Punkt angewendet , um die angehängte Sequenz zu entfernen . In jedem Fall ist so definiert, dass auf die Dinge vor dem ersten Punkt erweitert wird..\\
#1
\\
#2
#1
\\
#2
#2
\ifx\\#2\\
#2
\filename@ext
\let
\relax
\filename@ext
\edef
\filename@dot
.\\
\filename@base
\filename@dot
wird wie folgt definiert:
> \filename@dot=macro:
#1.\\->#1
Dieser \filename@parse
Mechanismus ist gut, hat aber einige Einschränkungen.
Beispielsweise wird angenommen, dass Dateinamen höchstens einen Punkt enthalten.
Beispielsweise wird angenommen, dass bei Dateinamen, die höchstens einen Punkt enthalten, der Punkt den Namen der Datei (ohne Erweiterung) von der Dateinamenerweiterung trennt, die wiederum nicht leer ist. Dateinamen, die mit einem Punkt enden (was auf einigen Dateisystemen völlig „legal“ ist), könnten Probleme verursachen.
Beispielsweise werden Sonderzeichen mit speziellen Kategoriecodes nicht berücksichtigt. Beispielsweise können bei Dateipfad-/Dateinamenspezifikationen, die geschweifte Klammern enthalten, die geschweiften Klammern ungleichmäßig sein oder entfernt werden und/oder Punkte und Schrägstriche „maskieren“, sodass sie nicht als Trennzeichen für abgegrenzte Argumente verwendet werden. Solche Dinge verursachen Probleme. Beispielsweise können Dateipfad-/Dateinamenspezifikationen, die Hashes enthalten, Probleme verursachen, wenn temporäre Makros wie \reserved@a
oder Makros definiert werden, die die Ergebnisse der Aufteilung der Dateipfad-/Dateinamenspezifikation enthalten.
Beispielsweise wird angenommen, dass ein einzelner „Treffer“ von \expandafter
/that, der einen einzelnen Erweiterungsschritt (→ darum geht es bei dem Begriff „Toplevel-Erweiterung“) auf dem ersten Token des Arguments auslöst, ausreicht, \filename@parse
um den gesamten Dateipfad/die gesamte Dateinamenspezifikation in Form einer Folge nicht erweiterbarer expliziter Zeichentoken zu erhalten. In Ihrem Szenario ist dies nicht der Fall und daher finden Versuche statt, Dinge aufzuteilen, während \sine
noch nicht erweitert ist und daher der Punkt, der den Dateinamen (ohne Erweiterung) von der Dateinamenerweiterung trennt, vom \filename@simple
Mechanismus noch nicht „gesehen“ werden kann. Daher „nimmt“ das Grafikpaket in Ihrem Szenario fälschlicherweise an, dass keine Dateinamenerweiterung angegeben ist. Falls das Grafikpaket „annimmt“ (ob die Annahme nun richtig oder falsch ist), dass keine Dateinamenerweiterung angegeben ist, versucht es es mit einigen Standarderweiterungen.
Anstatt mit wird es beispielsweise mit , , , usw. ../../code/waveletTest/data/results/synthetic/sine_100hz.pdf
versucht .
../../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
Deshalb ist die Eingabe von "H⟨zurückkehren⟩" wenn die Fehlermeldung auf der Konsole/dem Bildschirm erscheint, ergibt sich:
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.
Der Vorschlag von David Carlisle (Autor des GraphicX-Pakets), die Dateinamenerweiterung wegzulassen, .pdf
zielt darauf ab, dass in diesem Fall die Erweiterung vor der Überprüfung auf das Vorhandensein einer Dateinamenerweiterung zwar immer noch nicht in einer Weise erfolgt, die puristische Gemüter zufriedenstellen würde, die Annahme des GraphicX-Pakets, dass keine Dateinamenerweiterung angegeben wurde, jedoch richtig ist und das GraphicX-Paket daher die Standarderweiterungen auf eine Weise ausprobiert, die funktioniert – das GraphicX-Paket versucht es mit
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf
,
../../code/waveletTest/data/results/synthetic/sine_100hz.png
,
../../code/waveletTest/data/results/synthetic/sine_100hz.jpg
,
usw.
Das erste funktioniert bereits.
All diese Dinge können durch das Laden des Pakets behoben werdengrffile:
\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}
Übrigens:
In Ihrem ganz speziellen Fall können Sie den \filename@parse
Mechanismus dazu bringen, die Dateinamenerweiterung korrekt abzutrennen, indem Sie Folgendes hinzufügen \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}
Zumindest auf meinem System funktioniert das.
Beachten Sie, dass die Dateinamenerweiterung dabei korrekt abgetrennt wird.aber dass dies den Dateipfad nicht korrekt vom Dateinamen trennt.
Der Dateipfad wird als leer angenommen.
Die Sequenz \synthetic sine_100hz
wird als Dateiname angenommen.
Scheint, als ob das keine Rolle spielt.
Es handelt sich aber \filename@parse
um ein Makro des LaTeX 2ε-Kernels. Und am LaTeX 2ε-Kernel hat es in der letzten Zeit viele Änderungen und Neuerungen gegeben. Wahrscheinlich \filename@parse
funktioniert das auf deinem System nicht so wie auf meinem.
Ich gehe davon aus, dass "das einmalige Schlagen des ersten Tokens des Arguments, \expandafter
um aus der Top-Level-Erweiterung eines Makros die Dateipfad-/Dateinamenspezifikationen in Form nicht erweiterbarer expliziter Zeichentoken zu erhalten" nicht aus entfernt wird \filename@parse
.
Daher können Sie einige \romannumeral
-Erweiterungstricks anwenden, die einen Schlag erfordern, \expandafter
um die Dateipfad-/Dateinamenspezifikation zu liefern:
\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}
Was passiert hier?
\filename@parse
's \expandafer
tut "treffen" \romannumeral
.
Dann \romannumeral
- ausgelöste Sammlung eines TeX-⟨Nummer⟩-Menge ist in Bearbeitung:
%\romannumeral-triggered gathering of a TeX-number-quantity is in progress:
0\expandafter\synthetic\sine{100}
Nun findet LaTeX die Ziffer 0
und verwirft sie.
Nun beginnt der Prozess der Erfassung einer TeX-⟨Nummer⟩-Quantität wird in den Prozess des Sammelns weiterer Ziffern oder etwas umgewandelt, das das Sammeln der TeX- beendet.⟨Nummer⟩-Menge:
%\romannumeral-triggered gathering of more digits is in progress; digit "0" found.
\expandafter\synthetic\sine{100}
Nun expandiert LaTeX \expandafter
. Das Ergebnis der Expansion \expandafter
ist die Expansion \sine
:
%\romannumeral-triggered gathering of more digits is in progress; digit "0" found.
\synthetic sine_100hz.pdf
Jetzt erweitert LaTeX \synthetic
.
%\romannumeral-triggered gathering of more digits is in progress; digit "0" found.
\results synthetic/sine_100hz.pdf
Jetzt erweitert LaTeX \results
.
%\romannumeral-triggered gathering of more digits is in progress; digit "0" found.
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf
Jetzt findet LaTeX einen Punkt. Dieser Punkt ist keine Ziffer. Anders als ein Leerzeichen wird er nicht verworfen. Wie ein Leerzeichen beendet er die durch das Sammeln \romannumeral
von (Komponenten von) TeX ausgelöste Sammlung.⟨Nummer⟩-Mengen. Daher findet LaTeX nur die Ziffer/Zahl, 0
solange 0 keine positive Zahl ist. Bei nicht-positiven Zahlen \romannumeral
gibt LaTeX stillschweigend überhaupt kein Token zurück:
%\romannumeral done.
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf