4

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}
\addbibresource{\jobname.bib}

\usepackage{xstring}
\makeatletter

\DeclareFieldFormat{eprint:arxiv}{%
  arXiv\addcolon\space%
  \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}
jdm
  • 1,035

2 Answers2

5

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]{%
  arXiv\addcolon\space%
  \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
jdm
  • 1,035
  • 2
    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
5

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]
    }
  }
}
PLK
  • 22,776
  • 2
    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