“Arquivo não encontrado” ao usar comando em vez de texto simples

“Arquivo não encontrado” ao usar comando em vez de texto simples

Bom dia,

Estou tentando encontrar um método eficiente para acessar arquivos em uma pasta remota. Eu defini vários comandos para os caminhos.

A linha 6 do código abaixo funciona e inclui o arquivo correto, enquanto a linha 8 indica "arquivo não encontrado" - mas esses dois caminhos não deveriam ser exatamente iguais? Não tenho permissão para concatenar comandos como este?

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}}

Talvez eu não esteja vendo algo óbvio. Esta é a primeira vez que trabalho com nomes de caminhos em comandos. Alguém sabe o que estou perdendo?

Saúde

EDIT: Este é um exemplo de código completo:

\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}

Este código me mostra o arquivo que desejo. Se eu comentar na penúltima linha, recebo este erro:

File `../../code/waveletTest/data/results/synthetic/sine_100hz.pdf' not found. ...width=.3\linewidth]{\synthetic \sine{100}}

Responder1

No meu sistema, em algum estágio do processamento do seu \includegraphicscomando, você obtém a sequência:
\filename@parse{\synthetic\sine{100}}

\filename@parseé uma rotina do kernel 2ε do LaTeX que deve dividir seu argumento em

  1. Caminho para arquivo. O caminho para o arquivo deve ser armazenado na macro \filename@area.
  2. Nome do arquivo (sem extensão). O nome do arquivo (sem extensão) deve ser armazenado no formato \filename@base.
  3. Extensão do nome do arquivo. A extensão do nome do arquivo deve ser armazenada em \filename@ext. Caso não haja extensão, \filename@exté igual a \relax.

O que acontece:

No meu sistema \filename@parse, a sintaxe: é definida da seguinte forma:
\filename@parse{⟨file-path/filename-specification⟩}

> \filename@parse=macro:
#1->\let \filename@area \@empty \expandafter \filename@path #1/\\

Portanto, \filename@parseinicializa \filename@areapara igualar a macro \empty- a macro \emptysimplesmente desaparece do fluxo de token durante sua expansão de nível superior, sem processar nenhum argumento e entregando um texto de substituição que está vazio/que não consiste em nenhum token - e chama a rotina \filename@pathapós "acertar" o primeiro token do argumento com\expandafter uma veze anexando /\\ao resultado. (Caso o argumento #1esteja vazio, a barra anexada /será atingida, \expandaftero que não é prejudicial, pois o token de barra-caractere explícito (do catcode 12 (outro)) não é expansível.)

A rotina \filename@pathserá explicada em breve. Neste ponto, apenas até certo ponto:\filename@pathé recuado para processar uma sequência de tokens de caracteres explícitos não expansíveisque forma uma especificação de caminho de arquivo/nome de arquivo ( #1), seguido por um token de caractere de barra explícito /do código de categoria 12 (outro) e um token de símbolo de controle \\como delimitador/marcador para o final do caminho de arquivo/nome de arquivo -especificação.

Portanto, o "acerto com \expandafteruma vez" é feito \filename@parsecaso o argumento para fornecer a especificação do caminho do arquivo/nome do arquivo não consista em uma sequência de tokens de caracteres explícitos não expansíveis, mas seja formado por um token de macro cujo nível superior -expansion produz uma sequência de tokens de caracteres explícitos não expansíveis.
Este "acertar \expandafteruma vez" implica que com coisas como \includegraphics, que são usadas internamente \filename@parse, você pode fornecer especificações de caminho de arquivo/nome de arquivo apenas em termos de sequências de token, onde acertar o primeiro token da sequência \expandafteruma vez é suficiente para obter a sequência inteira de tokens de caracteres explícitos não expansíveis que formam a especificação do caminho do arquivo/nome do arquivo.

Esteja ciente de que, em seu cenário, um único "acerto com \expandafter" no primeiro token da sequência \synthetic \sine{100}não produz toda a especificação de caminho/nome de arquivo (totalmente expandida) em termos de uma sequência de tokens de caracteres explícitos não expansíveis, mas produz a sequência \results synthetic/\sine{100}onde mais trabalho de expansão precisa ser feito.

Portanto, a divisão/separação dos componentes (caminho para o arquivo, nome do arquivo sem extensão, extensão do nome do arquivo) não é feita corretamente por \filename@pathsuas rotinas subjacentes.

A rotina \filename@path, por sua vez, que "espera" que a especificação do caminho do arquivo/nome do arquivo seja fornecida em termos de uma sequência de tokens de caracteres explícitos não expansíveis, sintaxe: ; é folder/directory-separator , é definido da seguinte forma:
\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é um loop recursivo que em cada iteração anexa o próximo /segmento delimitado da especificação do caminho do arquivo/nome do arquivo à macro \filename@areaaté atingir o último segmento que denota o nome do arquivo. O próximo (e provavelmente o último) segmento está em #1. Os segmentos seguintes ao próximo segmento estão em #2. Assim, o indicador do último segmento é o vazio de #2.
O teste de vazio #2é: Ao atingir o último segmento, que denota o nome do arquivo, a macro é chamada para verificar se esse último segmento/nome de arquivo contém um ponto ( ) e, portanto, uma extensão de nome de arquivo precisa ser separada do nome do arquivo . Se uma extensão de nome de arquivo precisar ser separada, isso será feito por meio da macro .
\ifx\\#2\\⟨tokens in case #2 is empty⟩\else⟨tokens in case #2 is not empty⟩\fi
\filename@simple.\filename@dot

Ao chamar \filename@simple, sintaxe:, no último segmento delimitado que denota o nome do arquivo, a sequência é anexada ao último segmento. Assim, é possível reunir um argumento delimitado por pontos e um argumento delimitado por pontos e dependendo do vazio de detectar se um ponto presente no segmento ou o ponto anexado foi considerado o delimitador do argumento delimitado por pontos.
\filename@simple ⟨filename-specification in terms of a sequence of non-expandable explicit character-tokens⟩.\\
/.\\
\filename@simple#1\\#2#2

\filename@simpleé definido da seguinte forma:

> \filename@simple=macro:
#1.#2\\->\ifx \\#2\\\let \filename@ext \relax \else \edef \filename@ext {\filen
ame@dot #2\\}\fi \edef \filename@base {#1}

Se o último segmento/nome do arquivo não contiver um ponto, o .da sequência anexada .\\será considerado o delimitador de #1enquanto o \\-delimitado #2estará vazio. Caso contrário, o primeiro ponto do último segmento será considerado o delimitador de #1enquanto o \\-delimitado #2não estará vazio. Assim, o vazio de #2( \ifx\\#2\\...) é tomado como indicador se o último segmento forma um nome de arquivo sem extensão (separado por pontos) ou forma um nome de arquivo separado de uma extensão de arquivo por um ponto. Se #2estiver vazio, então \filename@ext" \let" é igual a \relax. Caso contrário, ao definir \filename@extvia \edef, \filename@doté aplicado às coisas atrás do primeiro ponto para remover a sequência anexada .\\. Em qualquer caso, \filename@baseestá definido para expandir para as coisas antes do primeiro ponto.

\filename@doté definido da seguinte forma:

> \filename@dot=macro:
#1.\\->#1

Este \filename@parsemecanismo é bom. Mas tem algumas restrições.

Por exemplo, presume-se que os nomes dos arquivos contenham no máximo um ponto.

Por exemplo, assume-se que com nomes de arquivos que contêm no máximo um ponto, o ponto separa o nome do arquivo (sem extensão) da extensão do nome do arquivo que por sua vez não está vazia. Nomes de arquivos que terminam com um ponto (que são perfeitamente "legais" em alguns sistemas de arquivos) podem causar problemas.

Por exemplo, caracteres especiais com códigos de categoria especiais não são levados em consideração. Por exemplo, com especificações de caminho de arquivo/nome de arquivo que contêm chaves, as chaves podem estar desequilibradas ou podem ser removidas e/ou podem "mascarar" pontos e barras para que não sejam usados ​​como delimitadores de argumentos delimitados. Essas coisas causam problemas. Por exemplo, especificações de caminho de arquivo/nome de arquivo que contêm hashes podem causar problemas quando se trata de definir macros temporárias como \reserved@aou as macros que contêm os resultados da divisão da especificação de caminho de arquivo/nome de arquivo.

Por exemplo, presume-se que um único "acerto" de \expandafter/that aciona uma única etapa de expansão (→é disso que se trata o termo "expansão de nível superior") no primeiro token do argumento de \filename@parseé suficiente para obter o caminho completo do arquivo / especificação de nome de arquivo em termos de uma sequência de tokens de caracteres explícitos não expansíveis. No seu cenário, este não é o caso e, portanto, as tentativas de dividir as coisas ocorrem enquanto \sineainda não estão expandidas e, portanto, o ponto que separa o nome do arquivo (sem extensão) da extensão do nome do arquivo ainda não pode ser "visto" pelo \filename@simplemecanismo. Portanto, no seu cenário, o pacote graphicx "assume" erroneamente que nenhuma extensão de nome de arquivo foi especificada. Caso o pacote graphicx "assuma" (seja a suposição correta ou errônea) que uma extensão de nome de arquivo não foi especificada, ele tenta com algumas extensões padrão.

Por exemplo, em vez ../../code/waveletTest/data/results/synthetic/sine_100hz.pdfdisso, tenta com
../../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,
etc.

É por isso que digitar "H⟨retornar⟩" quando a mensagem de erro aparece no console/tela produz:

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.

A sugestão de David Carlisle (que escreveu o pacote graphicx) de omitir a extensão de nome de arquivo .pdfvisa o fato de que, embora neste caso expandir as coisas antes de verificar a presença de uma extensão de nome de arquivo ainda não ocorrerá de uma forma que satisfaria mentes puristas, a suposição do pacote graphicx de que nenhuma extensão de nome de arquivo foi especificada estará correta e que, portanto, o pacote graphicx tenta as extensões padrão de uma maneira que funciona - o pacote graphicx tenta com
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf,
../../code/waveletTest/data/results/synthetic/sine_100hz.png,
../../code/waveletTest/data/results/synthetic/sine_100hz.jpg,
etc. .
O primeiro já dá certo.

Todas essas coisas podem ser resolvidas carregando o pacotearquivo 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}

Por falar nisso:

No seu caso muito especial, você pode enganar o \filename@parsemecanismo para separar a extensão do nome do arquivo corretamente adicionando \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}

Pelo menos no meu sistema isso funciona.

Esteja ciente de que isso separa a extensão do nome do arquivo corretamentemas isso não separa corretamente o caminho do arquivo do nome do arquivo.
O caminho do arquivo será considerado vazio.
A sequência \synthetic sine_100hzserá usada para o nome do arquivo.
Parece que isso não importa.

Mas \filename@parseé uma macro do kernel LaTeX 2ε. E houve muitas mudanças e inovações no kernel LaTeX 2ε no passado recente. Provavelmente o \filename@parseno seu sistema não funciona como no meu sistema.

Presumo que "acertar o primeiro token do argumento \expandafteruma vez para obter da expansão de nível superior de uma macro as especificações do caminho do arquivo/nome do arquivo em termos de tokens de caracteres explícitos não expansíveis" não será removido de \filename@parse.
Portanto, você pode aplicar alguns \romannumeraltruques de expansão que precisam de um golpe \expandafterpara entregar a especificação do caminho do arquivo/nome do arquivo:

\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}

O que acontece aqui?

\filename@parse's \expandaferfaz "hit" \romannumeral.
Então \romannumeral-reunião acionada de um TeX-⟨número⟩-quantidade está em andamento:

%\romannumeral-triggered gathering of a TeX-number-quantity is in progress:
0\expandafter\synthetic\sine{100}

Agora o LaTeX encontra o dígito 0e o descarta.
Agora, o processo de reunir um TeX-⟨número⟩-quantidade é transformada no processo de coleta de mais dígitos ou algo que encerra a coleta do TeX-⟨número⟩-quantidade:

%\romannumeral-triggered gathering of more digits is in progress; digit "0" found.
\expandafter\synthetic\sine{100}

Agora o LaTeX se expande \expandafter. O resultado da expansão \expandafteré a expansão \sine:

%\romannumeral-triggered gathering of more digits is in progress; digit "0" found.
\synthetic sine_100hz.pdf

Agora o LaTeX se expande \synthetic.

%\romannumeral-triggered gathering of more digits is in progress; digit "0" found.
\results synthetic/sine_100hz.pdf

Agora o LaTeX se expande \results.

%\romannumeral-triggered gathering of more digits is in progress; digit "0" found.
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf

Agora o LaTeX encontra um ponto. Esse ponto não é um dígito. Ao contrário de um token espacial, ele não é descartado. Como um token espacial, ele termina \romannumerala coleta acionada de (componentes do) TeX-⟨número⟩-quantidades. Portanto, o LaTeX encontrou apenas o dígito/número, 0enquanto 0 não é um número positivo. Com números não positivos \romannumeralsilenciosamente não retorna nenhum token:

%\romannumeral done.
../../code/waveletTest/data/results/synthetic/sine_100hz.pdf

informação relacionada