# How to use xstring commands in biblatex DeclareFieldFormat?

I'm trying to tweak a biblatex bibliography. One problem is the rendering of entries with eprint fields. Sometimes, I have something like

  eprint         = "hep-ph/0207124",


sometimes its

  eprint         = "0207124",
primaryClass   = "hep-ph",


but sometimes the class is given in both:

  eprint         = "hep-ph/0207124",
primaryClass   = "hep-ph",


I'd like to render all consistently in a format like "arXiv:hep-ph/0207124" for example. For this, I tried to customize \DeclareFieldFormat{eprint:arxiv}. My problem is that I can't properly use xstring commands like \IfSubStr or \StrDel in \DeclareFieldFormat. If I try to find primaryClass in eprint, it just doesn't work.

I've traced it down a bit. If #1 is hep-ph/0207124, then

\StrDel{#1}{\thefield{eprintclass}}


doesnt work. It doesn't find the string. I guess I need to make \thefield expand somehow. Even then, directly substituting the string doesn't work either:

\StrDel{#1}{hep-ph}


But it works partially if I use 0 or \string h (but not h) as an argument. I believe it has to do with the catcodes of the arguments. I tried a bunch of \detokenize, \expandafter, \expandarg, but without a systematic approach I can't get it to work.

So how do I use the string manipulation commands properly from within biblatex's field formats?

(Not-quite) minimal (not-quite) working example follows:

\documentclass{article}

\usepackage{filecontents}
\begin{filecontents}{\jobname.bib}
@article{Witten:2002ei,
author         = "Witten, Edward",
title          = "{Quest for unification}",
pages          = "604-610",
year           = "2002",
eprint         = "hep-ph/0207124",
archivePrefix  = "arXiv",
primaryClass   = "hep-ph",
SLACcitation   = "%%CITATION = HEP-PH/0207124;%%",
}
\end{filecontents}

\usepackage[style=numeric,sorting=none]{biblatex}

\usepackage{xstring}
\makeatletter

\DeclareFieldFormat{eprint:arxiv}{%
\iffieldundef{eprintclass}%
{#1}%
{%
eprint = #1 \par
class = \thefield{eprintclass} \par
number = \StrDel{#1}{\thefield{eprintclass}} \par
removing 0' = \StrDel{#1}{0} \par%
removing h' = \StrDel{#1}{h} \par%
removing \textbackslash string h' = \StrDel{#1}{\string h} \par%
}%
}

\makeatother

\begin{document}

\cite{Witten:2002ei}

\printbibliography
\end{document}

• I would work with DeclareSourceMap and modify all fields global. – Marco Daniel Jan 21 '14 at 19:19

The trick was to expand the field, and then convert it to the "other" catcode using a hack found here:

\edef\mytemporary{\thefield{eprintclass}}
\edef\myeprintclass{\expandafter\strip@prefix\meaning\mytemporary}
% then this works as expected:
\StrDel{#1}{\myeprintclass}


The following appends primaryClass + / only if the eprint field doesn't already start with it:

\makeatletter

\newbibmacro{eprint+arxiv}[1]{%
\iffieldundef{eprintclass}%
{#1}%
{%
\edef\mytemporary{\thefield{eprintclass}}%
\edef\myeprintclass{\expandafter\strip@prefix\meaning\mytemporary}%
\IfBeginWith{#1}{\myeprintclass/}%
{#1}%
{\myeprintclass/#1}%
}%
}

\DeclareFieldFormat{eprint:arxiv}{%
\ifhyperref%
{\href{http://arxiv.org/\abx@arxivpath/#1}{%
{\usebibmacro{eprint+arxiv}{#1}}%
}}%
{\usebibmacro{eprint+arxiv}{#1}}%
}

\makeatother

• Just for fun, you can avoid the double \edef with \IfBeginWith{#1}{\detokenize\expandafter{\romannumeral-Q\thefield{eprintclass}}/} instead of \IfBeginWith{#1}{\myeprintclass/}. Of course you must use {\thefield{eprintclass}/#1} as the fourth argument to \IfBeginWith. – egreg Jan 21 '14 at 22:22

It's cleaner to do this using biber and \DeclareSourcemap so that you don't have to complicate your style. You need to be using biber 1.9+biblatex 2.9 (both in development folders on SourceForge). Put this in your preamble:

\DeclareSourcemap{
\maps[datatype=bibtex]{
\map[overwrite=true]{
\step[fieldsource=primaryclass, match=\regexp{(.+)}, final]
\step[fieldsource=eprint, notmatch=\regexp{\A$1/}, final] \step[fieldsource=eprint] \step[fieldset=primaryclass, fieldvalue=/, append] \step[fieldset=primaryclass, origfieldval, append] \step[fieldsource=primaryclass, fieldtarget=eprint] } \map[overwrite=true]{ \step[fieldset=primaryclass, null] } } }  • I should probably explain why you need biber 1.9/biblatex 2.9 ... this is because the use of previous match buffer like "$1" in other matches was not possible until this version. – PLK Jan 22 '14 at 16:57