# How can I embed xstring commands (with commands as tokens) within other xstring commands?

I'd like to manipulate strings.

The following hello_en.txt should become hello.

This is related to, and quite possibly a duplicate of, Command doing the same job as StrBefore but being expandable. The problem there did not really solve mine, however.

# Example

I tried putting an \expandafter before the first \StrBefore, but it did not work.

\documentclass{article}
\usepackage{fontspec}
\usepackage{xstring}
\newcommand\mystring{hello\_en.txt}
\begin{document}
\StrBefore{\StrBefore{\mystring{}}{.}}{\_} % more complex DOES NOT WORK
\StrBefore{\StrBefore{hello\_en.txt}{.}}{\_} % simpler DOES NOT WORK
\end{document}


You must use something expandable, which \StrBefore isn't, and also be careful about the number of expansions.

\documentclass{article}

\usepackage{xstring}
\newcommand\mystring{hello\_en.txt}

\begin{document}

\expandarg
\StrBefore{\mystring}{.}[\temp]
\StrBefore{\temp}{\noexpand\_}

\end{document}


The default of xstring is \fullexpandarg, which is to be neutralized as fully expanding \_ is not something one wants in these cases.

If you try \edef\tmp{\_} you get, as replacement text,

\protect\global\let\\textunderscore\unhbox\voidb@x\kern .06em\vbox{\hrule width.3em}\\textunderscore


or, if you have \usepackage[T1]{fontenc},

\protect\T1\textunderscore


so in both cases it's not what you want \StrBefore to look for.

• Just for educational purposes, could you add what a fully expanded \_ is? Jul 9, 2015 at 11:21

Looks like a job for l3regex to me

\documentclass{article}
\usepackage{l3regex}
\ExplSyntaxOn
\cs_new_eq:NN \regexreplace \regex_replace_all:nnN
\ExplSyntaxOff
\newcommand\mystring{hello\_en.txt}
\begin{document}
\regexreplace{\c{_}.*}{}\mystring
\show\mystring
\end{document}


(In the regex, \c{_} is a control sequence matching exactly \_ while .* is standard regex syntax for 'any character'.)

• Thats funny because in the real document I am using ExplSyntax (LaTeX3). This question stems from iterating files: tex.stackexchange.com/questions/254247/…. I have a bunch of documents with ISO 639-1 language suffixes (en, de, etc.). They are contained in a master folder with the same name of the files but without the language suffix or extension. Jul 8, 2015 at 10:45
• @macmadness86 If you have a clear pattern for the names then a classical delimited macro will be the most efficient approach. Jul 8, 2015 at 10:49
• Your answer is my favorite, but I must mark egreg's answer, because it fits the question more accurately. Jul 9, 2015 at 11:02

A solution with stringstrings.

\documentclass{article}
\usepackage{stringstrings}
\newcounter{tmpctr}
\newcommand\preunderscore[1]{%
\whereischar[q]{#1}{_}%
\setcounter{tmpctr}{\theresult}%
\substring{#1}{1}{\thetmpctr}%
}
\begin{document}
\def\mystring{hello_en.txt}
\preunderscore{\mystring} is the truncated text.
\end{document}


If one wanted to specify the name with a quoted underscore, a small change is needed (which assumes there are no @ characters in the filename):

\documentclass{article}
\usepackage{stringstrings}
\newcounter{tmpctr}
\newcommand\preunderscore[1]{%
\convertchar[q]{#1}{\_}{@}%
\whereischar[q]{\thestring}{@}%
\setcounter{tmpctr}{\theresult}%
\substring{#1}{1}{\numexpr\thetmpctr-1}%
}
\begin{document}
\def\mystring{hello\_en.txt}
\preunderscore{\mystring} is the truncated text.
\end{document}