5

I am working on displaying source code for which I pass a path to a macro. Now I am wondering if it is possible using xstring or stringstrings to match from after the last delimiter, i.e. / to the end of the string to determine the filename.

Example: I might pass ../code/subfolder/project/code.java to the macro for which I want to extract the substring code.java. It seems easy to match the first occurrence of a character, but not the last.

7

No package is needed for that, you can use LaTeX's filename parser:

\documentclass{article}

\begin{document}

\makeatletter

\filename@parse{../code/subfolder/project/code.java}

[\filename@area]

[\filename@base]

[\filename@ext]

\end{document}
  • Accepted because it is the simplest answer (and most highly voted), but in all honesty all answers given are of equal high quality. Each answer has its own advantages/disadvantages. – Pieter Stroobants May 19 '15 at 22:36
4

Here is a method with xstring:

\documentclass{article}
\usepackage{xstring}
\newcommand*\filename[1]{%
    \IfSubStr{#1}/
        {\StrCount{#1}/[\ossepoccur]%
        \StrBehind[\ossepoccur]{#1}/\relax
        }
        {#1}%
}
\begin{document}
\filename{abc.foo}

\filename{../code/subfolder/project/code.java}
\end{document}
3

Here's a generic extractor of the last item in a delimited string:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\extractlast}{O{/}mo}
 {
  \seq_set_split:Nnn \l_stroobants_string_seq { #1 } { #2 }
  \IfNoValueTF { #3 }
   {
    \seq_item:Nn \l_stroobants_string_seq { -1 }
   }
   {
    \tl_set:Nx #3 { \seq_item:Nn \l_stroobants_string_seq { -1 } }
   }
 }
\seq_new:N \l_stroobants_string_seq
\ExplSyntaxOff

\begin{document}

\extractlast{../code/subfolder/project/code.java}

\extractlast[-]{a-b-c-def}[\test]

\texttt{\meaning\test}

\end{document}

The first optional argument is the delimiter, default /; the trailing optional argument is a macro name where the last item is stored, if not present, the item is printed.

enter image description here

A fully expandable version, but with a fixed delimiter; you're better not input an empty string, although a test for this can be easily added.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\extractlast}{m}
 {
  \stroobants_extractlast:nn #1 / \q_nil / \q_nil /
 }
\cs_new:Npn \stroobants_extractlast:nn #1 / #2 / \q_nil /
 {
  \str_if_eq:nnTF { #2 } { \q_nil }
   {% end of recursion
    #1
   }
   {% go on
    \stroobants_extractlast:nn #2 / \q_nil /
   }
 }
\ExplSyntaxOff

\begin{document}
\extractlast{../code/subfolder/project/code.java}

\edef\test{\extractlast{../code/subfolder/project/code.java}}
\texttt{\meaning\test}
\end{document}

enter image description here

2

Here is a way with stringstrings.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{stringstrings}
\def\fname#1{%
  \findchars[q]{#1}{/}%
  \edef\tmp{\theresult}%
  \convertchar[e]{x#1}{/}{ }%
  \getaword[q]{\thestring\ }{\numexpr\tmp+1\relax}%
  \edef\thefname{\thestring}%
}
\begin{document}
\fname{../code/subfolder/project/code.java}
The file is \thefname.
\end{document}

enter image description here

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.