Добрый день,
Я пытаюсь найти эффективный метод доступа к файлам в удаленной папке. Я определил несколько команд для путей.
Строка 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}}
Может быть, я не вижу чего-то очевидного. Я впервые работаю с путями в командах. Кто-нибудь знает, что я упускаю?
Ваше здоровье
EDIT: Это полный пример кода:
\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ε, которая разделяет свой аргумент на
- Путь к файлу. Путь к файлу должен быть сохранен в макросе
\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(other)) не подлежит расширению.)
Процедура \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
представляет собой рекурсивный цикл, который в каждой итерации добавляет следующий /
сегмент file-path/filename-specification с разделителем к макросу \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
а \\
-разделитель #2
будет пустым. В противном случае первая точка последнего сегмента будет взята за разделитель , #1
а \\
-разделитель #2
не будет пустым. Таким образом, пустота #2
( \ifx\\#2\\
...) берется как индикатор того, образует ли последний сегмент имя файла без (разделенного точкой) расширения или образует имя файла, отделенное от расширения файла точкой. Если #2
пусто, то равно \filename@ext
" " . В противном случае, при определении через , применяется к вещам за первой точкой для удаления присоединенной последовательности . В любом случае определено для расширения до вещей перед первой точкой.\let
\relax
\filename@ext
\edef
\filename@dot
.\\
\filename@base
\filename@dot
определяется следующим образом:
> \filename@dot=macro:
#1.\\->#1
Этот \filename@parse
механизм хорош. Но у него есть некоторые ограничения.
Например, предполагается, что имена файлов содержат не более одной точки.
Например, предполагается, что в именах файлов, содержащих не более одной точки, точка отделяет имя файла (без расширения) от расширения имени файла, которое, в свою очередь, не является пустым. Имена файлов, заканчивающиеся точкой (которые совершенно "законны" в некоторых файловых системах), могут вызвать проблемы.
Например, специальные символы со специальными кодами категорий не учитываются. Например, в случае спецификаций file-path/filename, содержащих фигурные скобки, фигурные скобки могут быть несбалансированными или могут быть удалены и/или могут «маскировать» точки и косые черты, чтобы их нельзя было использовать в качестве разделителей аргументов с разделителями. Такие вещи вызывают проблемы. Например, спецификации file-path/filename, содержащие хэши, могут вызывать проблемы при определении временных макросов, таких как \reserved@a
или макросы, которые содержат результаты разделения спецификации file-path/filename.
Например, предполагается, что одного "удара" \expandafter
/, который запускает один шаг расширения (→вот что означает термин "toplevel-expansion") на первом токене аргумента достаточно \filename@parse
для получения всей спецификации пути к файлу/имени файла в терминах последовательности нерасширяемых явных символьных токенов. В вашем сценарии это не так, и поэтому попытки разделения происходят, пока \sine
еще не расширен, и поэтому точка, которая отделяет имя файла (без расширения) от расширения имени файла, \filename@simple
пока не может быть "увидена" механизмом. Поэтому в вашем сценарии графический пакет ошибочно "предполагает", что расширение имени файла не указано. В случае, если графический пакет "предполагает" (будь то предположение правильным или ошибочным), что расширение имени файла не указано, он пытается использовать некоторые расширения по умолчанию.
Например, вместо ../../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.
Предложение Дэвида Карлайла (автора пакета graphicx) опустить расширение имени файла .pdf
направлено на то, что, хотя в этом случае расширение файлов перед проверкой наличия расширения имени файла все равно не будет происходить способом, который бы удовлетворил пуристские умы, предположение пакета graphicx об отсутствии указанного расширения имени файла будет верным, и поэтому пакет graphicx пробует расширения по умолчанию способом, который работает — пакет graphicx пробует с
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf
,
../../code/waveletTest/data/results/synthetic/sine_100hz.png
,
../../code/waveletTest/data/results/synthetic/sine_100hz.jpg
,
и т. д.
Первый способ уже работает.
Все эти проблемы можно решить, загрузив пакетgrffile:
\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
-expansion-trickery, которая требует одного нажатия на \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
's \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