1

I use biblatex package. I have a problem with changing multiple citations punctuation.

I want use such commands as \cites and \parentcites follows:

\cites{AuthorYYYY,AuthorYYYY,AuthorYYYY}

I have in output:

Author1 YYYY; Author2 YYYY; Author3 YYYY.

But I want to have:

Author1 YYYY and Author2 YYYY

Author1 YYYY, Author2 YYYY, and Author3 YYYY

Author1 YYYY, p. 1-3, Author2 YYYY, and Author3 YYYY, pp. 4 and 12-14

How do I change it?

Thank you!

percusse
  • 157,807
Mikhail
  • 35

2 Answers2

5

I'm late for the party, but I think now biblatex allows you to do that.

Consider the example:

\documentclass{article}
\usepackage{geometry}
\usepackage[citestyle=authoryear-comp]{biblatex}
\addbibresource{biblatex-examples.bib}
\begin{document}
\cites{glashow,herrmann}

\cites{glashow,herrmann,kastenholz}

\cites[1-3]{glashow}{herrmann}[\ppno~4 and~12--14]{kastenholz}
\end{document}

which prints:

enter image description here

If we redefine \multicitedelim we can make it print different delimiters, depending on the number of citations (stored in the citetotal counter) and the number of the current citation (stored in the citecount counter):

\renewcommand*{\multicitedelim}{%
  \iflastcitekey
    {%
      \ifboolexpr{
            test {\ifnumgreater{\value{citetotal}+\value{multicitetotal}-1}{2}}
         or test {\ifnumgreater{\value{lastcitetotal}+\value{citetotal}}{2}}
       }
       {\finalandcomma}
       {}%
      \addspace\bibstring{and}\space
   }
   {\addcomma\space}%
  \ifnumequal{\value{citetotal}}{\value{citecount}}
   {\setcounter{lastcitetotal}{\value{citetotal}}}
   {}%
}

The above definition checks if the current citation key is the last one in the comma separated list using \iflastcitekey. If it's not the last citation, just print \addcomma\space (i.e., ,␣). Otherwise, if it's the last key, we check if the expression \value{citetotal}+\value{multicitetotal}-1 or \value{lastcitetotal}+\value{citetotal} are greater than two, and if they are, print a \finalandcomma and then \addspace\bibstring{and}\space in all cases (,␣and␣).

The first expression is less or equal the total number of citations in the multi-cite command, so if there are multiple citations it will ensure the \finalandcomma. This expression will only fail in the case \cites{one,two}{three}, where multicitetotal is two and citetotal is 1 when three is being processed. In this case the expression evaluates to 2 and the \finalandcomma is not printed, whereas it should.

To work around that exception I added a bodge temporary counter which stores the previous citetotal. In the case of the exception, lastcitetotal will be 2 and citetotal, 1, and their sum will be larger than 2 so the \finalandcomma will be printed.

Adding that definition to our example:

\documentclass{article}
\usepackage{geometry}
\usepackage[citestyle=authoryear-comp]{biblatex}
\addbibresource{biblatex-examples.bib}
\newcounter{lastcitetotal}
\renewcommand*{\multicitedelim}{%
  \iflastcitekey
    {%
      \ifboolexpr{
            test {\ifnumgreater{\value{citetotal}+\value{multicitetotal}-1}{2}}
         or test {\ifnumgreater{\value{lastcitetotal}+\value{citetotal}}{2}}
       }
       {\finalandcomma}
       {}%
      \addspace\bibstring{and}\space
   }
   {\addcomma\space}%
  \ifnumequal{\value{citetotal}}{\value{citecount}}
   {\setcounter{lastcitetotal}{\value{citetotal}}}
   {}%
}
\begin{document}
\pagestyle{empty}
\cites{glashow,herrmann}

\cites{glashow,herrmann,kastenholz}

\cites[1-3]{glashow}{herrmann}[\ppno~4 and~12--14]{kastenholz}
\end{document}

we get:

enter image description here

  • biblatex has the test \iflastcitekey that should also take into account multicites. – moewe Apr 04 '19 at 15:48
  • I should also note that the p.~ in [p.~1--3] is superfluous (since biblatex automatically adds the "p."/"pp." in postnotes if they contain only a page range) and that in [pp.~4 and~12--14] I would prefer [\ppno~4 and~12--14] (here the page detection will yield false because of the and, so we need to ask for the "pp." explicitly). – moewe Apr 04 '19 at 15:51
  • Getting closer ... \renewcommand*{\multicitedelim}{% \iflastcitekey {\ifnumgreater{\value{citetotal}+\value{multicitetotal}-1}{2} {\finalandcomma} {}% \addspace\bibstring{and}\space} {\addcomma\space}} works almost except for \cites{glashow,herrmann}{kastenholz} because I couldn't find a way to count the total across several multicites. Hence I used \value{citetotal}+\value{multicitetotal}-1 which should be \leq the actual total. – moewe Apr 04 '19 at 16:09
  • @moewe Wow, I left for lunch and when I came back ;) Hm... What if I remember the last citetotal and use that to check for that exception? Like this? Seems to work, what do you think? Oh, and if I replace [p.~1--3] by [1--3] or [1-3] I get pp. 1–3 instead of p. 1–3. Is that expected? – Phelype Oleinik Apr 04 '19 at 18:00
  • 2
    Yes, "pp." instead of "p." is expected (at least for English texts). Traditionally, "p." stands for "page" while "pp." stands for the plural "pages". Since 1-3 is a page range it would be prefixed with "pp." and not "p.". (Other languages might be different, in German we use "S." for both singular and plural.) – moewe Apr 04 '19 at 19:38
  • 1
    Finally managed to wrap my head around the lastcitetotal idea. I'm pretty much convinced that it should do the right thing here. Of course the additional counter is not pretty, but I'm not sure if it is possible to get a real 'overall citecount' ready... – moewe Apr 04 '19 at 20:05
  • 2
    @moewe Oh, I agree, it's a very clumsy approach. I think it should be possible to have the “overall citecount” as well, mainly because when the first \multicitedelim is inserted we already know how much is multicitetotal, so it means biblatex already scanned the list of [<postnote>]{<citation>}s once, it just didn't count the citations inside that list. Of course I might be reading something wrong here. When I have some time I'll take a look to see if I manage to do something nicer than lastcitetotal, meanwhile I'll point that in my answer. Thanks for the help :) – Phelype Oleinik Apr 04 '19 at 21:35
  • I think an 'overall citecount' would be possible (we just have to remember the previous and reset it at the beginning). But usually a citecount is accompanied by a citetotal and I can't think of a way to get 'overall citetotal' to work. As far as I understand, biblatex's multicite works roughly as follows: First it collects and counts the multicite groups (that is what multicitecount is for), then each multicite group is passed to one normal cite command. A cite command first counts the keys it gets (for citecount) and then starts its work. .... – moewe Apr 05 '19 at 03:59
  • ... This would mean that at the first constituent cite of a multicite we know how many multcites there are going to be, but not how many keys there are going to be in each. That is only counted once the constituent cite is actually executed. – moewe Apr 05 '19 at 04:01
  • @moewe I think I managed to implement an “overall citecount” in biblatex (not extensively tested, though :-). The code (and the diff against the one in TL2018) and a test document. If you think it's worth it I'd be happy to add a pull request to the biblatex repo :-) – Phelype Oleinik Apr 05 '19 at 18:57
  • Thank you very much for looking into this. I have to admit that I don't quite understand all the tricks you pulled off. I ran a few tests, though, and found two issues: (1) It seems that the new counters leak in case one uses only a single \cite command. (2) The trick to count the entries per multi-cite group does not drop duplicate entries (if they are indeed dropped). An example is at https://gist.github.com/moewew/df9eb6e4f730350084b9a3fb371621a9 – moewe Apr 05 '19 at 19:23
  • @moewe Hm. I imagined that the smuggling thingy would cause trouble... And I completely overlooked the duplicate entries. I'll need some time to investigate this. Perhaps over the weekend. I'll get back to you when I find a solution :-) – Phelype Oleinik Apr 05 '19 at 19:32
  • I'd have probably just used global assignments and would reset them as necessary to avoid the smuggling (which I don't know a lot/anything about). But the more tricky issue is properly counting the number of items per 'group'. It feels a bit wrong to count things at the early stage that would be required to get the correct overallcitetotal, especially because the counting will be repeated at a later processing step. But that seems to be the only way ... – moewe Apr 05 '19 at 20:22
  • I answered on https://gist.github.com/moewew/df9eb6e4f730350084b9a3fb371621a9. Your name did not @-autocomplete, so I'll just ping you here. – moewe May 18 '19 at 12:03
2

You can change the general punctuation between consecutive citations that are passed to the same cite-command by changing \multicitedelim. So, something like \renewcommand{\multicitedelim}{\addcomma\space} should change your output to

Author1 YYYY, Author2 YYYY, Author3 YYYY

for \cites{AuthorYYYY,AuthorYYYY,AuthorYYYY}.

Now you even want a different treatment with 'and' in case of two citations and comma between all citations, except the last where it should be 'and' with Oxford-comma in case of more than two citations. I think this is not easily possible, because seemingly biblatex does not distinguish between the delimiter for the last item and all other items separately, as it does for the author-name and list delimiters.