4

This code crashes because I'm including the macro tmp into the label command. Reading this forum, especially What is the difference between Fragile and Robust commands? , I thought that the \protect I put in front of \tmp should fix the problem, but it doesn't. Could somebody please explain how to get it to work? Thanks very much for any suggestions

\documentclass{amsart}
\usepackage{soul}
\usepackage{xstring}
\begin{document}
\def\tmp{fig:\StrBefore{file.png}{.}}
\tmp
\begin{figure}
\caption{nothing}
\label{\protect\tmp}
%\label{\tmp}
\end{figure}
\end{document}
  • When it comes to processing file-paths and/or filenames it is always good to know whether folder-names/directory-names/filenames/filename-extensions with unbalanced curly braces and/or hashes can play a rôle. E.g., something like filen#{.ex} is a valid filename with filename-base filen#{ and filename-extension ex} in some file-systems. ... It is also good to know whether expansion of macros shall take place when obtaining tokens that form file-paths/filenames. – Ulrich Diez Apr 4 at 20:19
4

I would just use the ability of xstring to store the result of the extraction in a macro.

\documentclass{amsart}
\usepackage{soul}
\usepackage{xstring}
\begin{document}
\StrBefore{file.png}{.}[\tmp]
\edef\tmp{fig:\tmp}
\tmp
\begin{figure}
\caption{nothing}
\label{\tmp}
\end{figure}
\end{document}

enter image description here

| improve this answer | |
  • All three suggestions work, I accepted this one just because I like the xstring package and all it does, i.e., hysteresis. Thanks to all – Leo Simon Apr 5 at 19:29
5

The macros of xstring are not, generally, expandable, which is needed here. Thus, I change over to listofitems, which produces expandable results.

\documentclass{amsart}
\usepackage{soul}
\usepackage{listofitems}
\begin{document}
\setsepchar{.}
\readlist\fileroot{file.png}
\edef\tmp{fig:\fileroot[1]}
\tmp
\begin{figure}
\caption{nothing}
\label{\tmp}
\end{figure}

I refer to figure \ref{fig:file}
\end{document}

enter image description here

And here's a version that doesn't even need listofitems:

\documentclass{amsart}
\usepackage{soul}
\newcommand\fileroot[1]{\filerootaux#1.\relax}
\def\filerootaux#1.#2\relax{#1}
\begin{document}
\edef\tmp{fig:\fileroot{file.png}}
\tmp
\begin{figure}
\caption{nothing}
\label{\tmp}
\end{figure}

I refer to figure \ref{fig:file}
\end{document}
| improve this answer | |
2

The argument to \label should be something that eventually becomes a string of characters, but \StrBefore eventually becomes instructions to print some characters, which is a very different thing.

It's simpler, unless your file names can have multiple periods in their names.

\documentclass{article}

\makeatletter
\newcommand{\stripext}[1]{\strip@ext#1.\@nil}
\def\strip@ext#1.#2\@nil{#1}
\makeatother

\begin{document}

\stripext{file.png}
\label{\stripext{file.png}}

\stripext{filenoext}
\label{\stripext{filenoext}}

\end{document}

The trick is to use a macro with delimited arguments. If we do \stripext{file.png}, we get

\strip@ext file.png.\@nil

and the macro \strip@ext uses as #1 whatever comes along until the first .; in this case it is file.

In the case of \stripext{filenoext}, we get

\strip@ext filenoext.\@nil

and things are good as well. In the first case #2 is png., in the second case it is empty; but the second argument is simply thrown away.

The .aux file from the code above will contain

\relax
\newlabel{file}{{}{1}}
\newlabel{filenoext}{{}{1}}

so you see it's as expected.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.