«Файл не найден» При использовании команды вместо обычного текста

«Файл не найден» При использовании команды вместо обычного текста

Добрый день,

Я пытаюсь найти эффективный метод доступа к файлам в удаленной папке. Я определил несколько команд для путей.

Строка 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ε, которая разделяет свой аргумент на

  1. Путь к файлу. Путь к файлу должен быть сохранен в макросе \filename@area.
  2. Имя файла (без расширения). Имя файла (без расширения) должно быть сохранено в \filename@base.
  3. Расширение имени файла. Расширение имени файла должно храниться в \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

Связанный контент