Problem using \noopsort to sort on 'year' using natbib

In my efforts to familiarise myself with BIBTeX and natbib, I've been playing with the xampl.bib database which is shipped with the TeXLive 2011 distribution. I created a document (using the plainnat.bststyle) which cited every entry in the database. Compiling the document produced console output as follows (after running PDFLaTeX for the third time):

(./xampl-citations.tex
! Missing = inserted for \ifnum.
\def
l.15 {\citeref{book-full}
}
?


\citeref is a command I define so that I can change the citation style easily. It appears as follows in the document preamble:

\newcommand{\refcolor}{\color{Black}}
\newcommand{\citeref}{\refcolor \citep}


After a process of elimination (ie by changing entries in the xampl.bib database using JabRef), I've pinned the problem down to entries in the 'year' field of the following form:

{\noopsort{1973c}}1981


As far as I can tell \noopsort is correctly defined in the preamble of the xampl.bib file:

@PREAMBLE{ "\newcommand{\noopsort}[1]{} "
# "\newcommand{\printfirst}[2]{#1} "
# "\newcommand{\singleletter}[1]{#1} "
# "\newcommand{\switchargs}[2]{#2#1} " }


As you might imagine, I've done a fair amount of searching around to see if anyone else has reported a similar problem, and I've found a question on this resource which suggests that the problem might be an excess of curly brackets in the .bib file:

natbib-error-when-citing-paper-with-similar-authors-and-same-year

Indeed, an example section from my xampl.bib file does suggest that the entries contain a superfluous pair of curly brackets:

@BOOK{book-full,
title = {Seminumerical Algorithms},
year = {{\noopsort{1973c}}1981},
author = {Donald E. Knuth},
volume = {2},
series = {The Art of Computer Programming},
edition = {Second},
month = {10~} # jan,
note = {This is a full BOOK entry},
fileno = {91}
}


The problem is – what do I do about it? The way my set-up works is that I hold my master database in EndNote and then export entries (required fields only) into JabRef where I perform the necessary tweaks for LaTeX. This system works well for me, so I don't particularly want to change it. However, if surplus curly brackets is the cause of the problem, then how do I prevent them appearing in the .bib file?

This is not a hypothetical question, because I will need occasionally to adjust the sort order of entries in my thesis bibliography – so I need to find a way to do it. If the \noopsort method cannot be made to work, are there any other options?

-

The problem is the supplementary pair of braces, which is however necessary for correct sorting. You should try biblatex, really, because it provides different fields for sorting dates.

A possible patch is to write, after loading natbib,

\makeatletter
\let\NAT@bare@aux\NAT@bare
\def\NAT@bare#1(#2){%
\begingroup\edef\x{\endgroup
\unexpanded{\NAT@bare@aux#1}(\@firstofone#2)}\x}
\makeatother


This will swallow the offending part, while keeping the correct sorting order.

The problem is in what's presented to LaTeX and natbib to interpret. If you look at the .bbl file, you'll see that the entry starts with

\bibitem[Knuth({\noopsort{1973c}}1981)]{book-full}


Now natbib uses this to produce the results from \citep{book-full} (or \citet), by applying various commands. The relevant one (that I found with some grep search) is \NAT@bare that requires its arguments in the form

\def\NAT@bare#1(#2)#3(@)#4\@nil#5{%


The relevant part is #1(#2), which is derived from the argument to \bibitem in brackets; natbib wants to perform a numeric check, assuming that what's in parentheses is the year. But it finds {\noopsort{1973c}}1981 and this breaks off. So I make an alias to the original \NAT@bare command, calling it \NAT@bare@aux and do

\def\NAT@bare#1(#2){%
\begingroup\edef\x{\endgroup
\unexpanded{\NAT@bare@aux#1}(\@firstofone#2)}\x}


So, when natbib wants to execute \NAT@bare (it's so instructed by other macros), it will take the argument Knuth({\noopsort{1973c}1981}) and perform an\edef; thus\x will be defined as the result of completely expanding

\endgroup\unexpanded{\NAT@bare@aux Knuth}(\@firstofone{\noopsort{1973c}}1981)


The job of \@firstofone is just to strip the braces, and the expansion of \noopsort{1973c} is just empty. So at the end LaTeX will see

\NAT@bare@aux Knuth(1981)


which is in the right format. The \endgroup balances the \begingroup and vanishes together with the definition of \x which has already done its job.

If the entry is normal, say \bibitem[Author(2012)] (by the way, Happy New Year), \x will be defined as the full expansion of

\endgroup\unexpanded{\NAT@bare@aux Author}(\@firstofone 2012)


and \@firstofone 2 will simply return 2, so in the end LaTeX will see

\NAT@bare@aux Author(2012)


as it should.

-
Many thanks @egreg, that does the trick! I wish I understood the code above, but I guess I need to learn to walk before I can run. It has occurred to me to have a look at biblatex, but I thought I'd get familiar with bibtex first. My thesis isn't due for another 2 years and 9 months, so I've got plenty of time to get to grips with the intracies of latex! – Mark Birtwistle Jan 1 '12 at 11:52
@MarkBirtwistle I've added some explanations – egreg Jan 1 '12 at 13:49
@Mark: I highly recommend biblatex! Have a look at tex.stackexchange.com/questions/25701/… and tex.stackexchange.com/questions/5091/…. – lockstep Jan 1 '12 at 13:49
@egreg, many thanks for your comprehensive explanations – I will need to spend a little time going through them and trying to understand them. @lockstep, you're very persuasive. As I have a full 2 years and 9 months before my thesis submission date, I have plenty of time to get my head around biblatex'! – Mark Birtwistle Jan 3 '12 at 10:40
@MarkBirtwistle Study biblatex, then. It's vastly more powerful than natbib. – egreg Jan 3 '12 at 10:42

I notice that your \refcite command invokes natbib's \citep command, but it does so without explicitly noting that \citep takes an argument. A possible solution -- I say possible because I haven't actually tried it out -- would be to have the following commands in the preamble:

\usepackage[svgnames]{xcolor}  % or: \usepackage{color}
...
\providecommand{\noopsort}[1]{}
\newcommand{\refcolor}{Black}
\newcommand{\citeref}[1]{\textcolor{\refcolor}{\citep{#1}}}

-
funnily enough I was thinking along the same lines – it would be useful to be able to insert page and/or chapter numbers into a citation. After a lot of playing around, I've managed to get it to work with a slight modification of the code you propose: – Mark Birtwistle Jan 1 '12 at 11:18
Good God @Mico, five minutes doesn't give you much time for editing! The modified code is \newcommand{\citeref}[1]{\refcolor \citep[#1]}. In the text I cite references either as \citeref{}{_citationkey_} or \citeref{p _xx_}{_citationkey_}. Many thanks for your input, much appreciated. – Mark Birtwistle Jan 1 '12 at 11:28