2

Using the excellent solution to compress citations for @set members provided by moewe in this question results in an unexpected behaviour of the compression mechanism if members of different sets are combined in one \cite command. Obviously the internal change of the @set is not reliable recognized so the macro gets confused.

In the following MWE I have implemented a check for the change of sets that can be switched on or off by \toggletrue{adapted} resp. \togglefalse{adapted} to reproduce both variations.

What I just don't get is why moewes solution does not work as expected - so basically it's more a question out of curiosity...

The result of the MWE is

enter image description here

where in line 3 the original code is used and in line 4 the adapted one.

MWE:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[ngerman]{babel}
\usepackage[babel,german=quotes]{csquotes}
\usepackage[backend=biber,style=numeric-comp,mcite,subentry,sorting=nty,sortsets=true,backref=false]{biblatex}

\usepackage{filecontents}
\begin{filecontents*}{\jobname.bib}
@Book{fish:drugs,
  mainsubtitle = {Drugs and Society},
  year = {2006},
  editor   = {Jefferson M. Fish},
  maintitle= {U.S.~public policy},
  publisher= {Rowman \& Littlefield Publishers, Inc},
  location = {Lanham, Maryland},
  isbn = {0-7425-4245-9},
  sortname = {Jefferson M. Fish},
  sorttitle= {U.S. public policy Drugs and Society},
  options  = {dataonly},
}
@Set{set:fish:drugs,
  entryset = {fish:drugs:gable:alt,fish:drugs:cleveland:use,fish:drugs:evans:intro},
  options  = {multivolumehead=fish:drugs},
}
@Inbook{fish:drugs:evans:intro,
  crossref   = {fish:drugs},
  author = {Richard M. Evans and Stanley Neustadter},
  chapter= {6},
  title  = {Legalization: An Introduction},
  pages  = {129-148},
  sorttitle  = {06 Legalization: An Introduction},
  options= {dataonly},
}
@Inbook{fish:drugs:cleveland:use,
  crossref   = {fish:drugs},
  author = {Mary M. Cleveland},
  chapter= {9a},
  title  = {Use, 'Abuse', Adverse Health Effects, and Addiction},
  pages  = {197-200},
  sorttitle  = {09 Use, Abuse, Adverse Health Effects, and Addiction},
  options= {dataonly},
}
@Inbook{fish:drugs:gable:alt,
  crossref   = {fish:drugs},
  author = {Robert S. Gable},
  chapter= {7},
  title  = {Acute Toxicity of Drugs versus Regulatory Status},
  pages  = {149-161},
  sorttitle  = {07 Acute Toxicity of Drugs versus Regulatory Status},
}
@Book{A,
  author  = {René Goscinny and Albert Uderzo},
  maintitle   = {Asterix und Obelix},
  year    = {1959--2018},
  publisher   = {Dargaud},
  location= {Paris},
  volumes = {99},
  options = {dataonly},
}
@Set{set:A,
  entryset= {A:V1,A:V2,A:V3,A:V4,A:V5,A:V6},
  options = {multivolumehead=A},
}
@Book{A:V1,
  crossref= {A},
  title   = {Asterix der Gallier},
  sorttitle   = {Goscinny Rene Uderzo Albert Asterix und Obelix 01},
  year    = {1959},
  isbn    = {1234567890123},
  volume  = {1},
}
@Book{A:V2,
  crossref= {A},
  title   = {Asterix und Kleopatra},
  sorttitle   = {Goscinny Rene Uderzo Albert Asterix und Obelix 02},
  year    = {1968},
  isbn    = {2345678901234},
  volume  = {2},
}
@Book{A:V3,
  crossref= {A},
  title   = {Asterix als Gladiator},
  sorttitle   = {Goscinny Rene Uderzo Albert Asterix und Obelix 03},
  year    = {1969},
  isbn    = {3456789012345},
  volume  = {3},
}
@Book{A:V4,
  crossref= {A},
  title   = {Der Kampf der Häuptlinge},
  sorttitle   = {Goscinny Rene Uderzo Albert Asterix und Obelix 04},
  year    = {1969},
  isbn    = {4567890123456},
  volume  = {4},
}
@Book{A:V5,
  crossref= {A},
  title   = {Die goldene Sichel},
  sorttitle   = {Goscinny Rene Uderzo Albert Asterix und Obelix 05},
  year    = {1970},
  isbn    = {5678901234567},
  volume  = {5},
}
@Book{A:V6,
  crossref= {A},
  title   = {Tour de France},
  sorttitle   = {Goscinny Rene Uderzo Albert Asterix und Obelix 06},
  year    = {1970},
  isbn    = {6789012345678},
  volume  = {6},
}
@Book{DHS:base,
  editor= {{Deutsche Hauptstelle für Suchtfragen e.~V.}},
  sortname  = {{Deutsche Hauptstelle für Suchtfragen}},
  year  = {2017},
  url   = {www.dhs.de},
  urldate   = {2018-04-30},
  maintitle = {Suchtmedizinische Reihe},
  options   = {dataonly},
}
@Book{DHS:nik,
  crossref  = {DHS:base},
  title = {Tabakabhängigkeit},
  sorttitle = {Deutsche Hauptstelle für Suchtfragen Suchtmedizinische Reihe 01},
  volume= {1},
  isbn  = {978-3-937587-00-4},
}
@Book{DHS:alk,
  crossref  = {DHS:base},
  title = {Alkoholabhängigkeit},
  sorttitle = {Deutsche Hauptstelle für Suchtfragen Suchtmedizinische Reihe 02},
  volume= {2},
  isbn  = {978-3-937587-01-1},
}
@Book{DHS:drogen,
  crossref  = {DHS:base},
  title = {Drogenabhängigkeit},
  sorttitle = {Deutsche Hauptstelle für Suchtfragen Suchtmedizinische Reihe 04},
  volume= {4},
  isbn  = {978-3-937587-03-5},
}
@Set{DHS:SMR,
  crossref  = {DHS:base},
  entryset  = {DHS:alk,DHS:nik,DHS:drogen},
  options   = {multivolumehead=DHS:base},
}
\end{filecontents*}

\newtoggle{adapted}\togglefalse{adapted}

\makeatletter
% compress set member citations
% code by moewe
% https://tex.stackexchange.com/questions/416444/biber-and-biblatex-reference-to-multiple-subentries
% https://tex.stackexchange.com/questions/470391/compress-citation-of-multiple-set-members-in-biblatex
\newcounter{cbx@tempcntc}
\newcounter{cbx@tempcntd}
\renewbibmacro*{cite:init}{%
  \global\boolfalse{cbx:parens}%
  \global\undef\cbx@lasthash
  \global\undef\cbx@lastnumber
  \global\undef\cbx@lastprefix
  \global\undef\cbx@lastcount
  \setcounter{cbx@tempcnta}{0}%
  \setcounter{cbx@tempcntb}{-2}%
  \setcounter{cbx@tempcntc}{0}%
  \setcounter{cbx@tempcntd}{-1}}

\renewbibmacro*{cite:comp:inset}{%
  \iftoggle{adapted}% new
    {\ifdef{\cbx@lastnumber}
       {\iffieldequals{labelnumber}{\cbx@lastnumber}
          {}% same label number
          {%  label number changed
           \usebibmacro{cite:dump}%
           \ifnumgreater{\value{cbx@tempcntb}}{-1}
          {\multicitedelim%
            \usebibmacro{cite:init}}% cite reset
          {}}}%%%<- terminate previous entry
       {}}
     {}% end new
    \stepcounter{cbx@tempcntd}%
  \ifboolexpr{
    (( test {\iffieldundef{labelprefix}} and test {\ifundef\cbx@lastprefix} )
       or
       test {\iffieldequals{labelprefix}{\cbx@lastprefix}})
   and test {\iffieldequals{labelnumber}{\cbx@lastnumber}}
    }
    {}
    {\setcounter{cbx@tempcntc}{0}%
     \usebibmacro{cite:dump}%
     \ifnumgreater{\value{cbx@tempcntb}}{-1}
       {\multicitedelim}
       {}}%
    \printtext[bibhyperref]{%
    \ifboolexpr{
      (( test {\iffieldundef{labelprefix}} and test {\ifundef\cbx@lastprefix} )
         or
         test {\iffieldequals{labelprefix}{\cbx@lastprefix}})
     and test {\iffieldequals{labelnumber}{\cbx@lastnumber}}
      }
    {}
    {\printfield{labelnumber}%
     \savefield{labelnumber}{\cbx@lastnumber}}%
        \ifnumequal{\thefield{entrysetcount}}{\value{cbx@tempcntd}}
      {\savefield{entrykey}{\cbx@lastkey}%
       \savefield{entrysetcount}{\cbx@lastcount}%
       \stepcounter{cbx@tempcntc}}
      {\usebibmacro{cite:dump}%
       \ifnumgreater{\value{cbx@tempcntd}}{0}
         {\multicitedelim}
         {}%
       \printfield{entrysetcount}}}%
  \setcounter{cbx@tempcntd}{\thefield{entrysetcount}}%
  \setcounter{cbx@tempcntb}{-1}}

\renewbibmacro*{cite:dump}{%
  \ifnumgreater{\value{cbx@tempcntc}}{0}
    {\ifnumgreater{\value{cbx@tempcntc}}{1}
       {\bibrangedash}
       {\multicitedelim}%
     \bibhyperref[\cbx@lastkey]{%
     \printtext[entrysetcount]{\cbx@lastcount}}}
    {}%
  \setcounter{cbx@tempcntc}{0}%
  \ifnumgreater{\value{cbx@tempcnta}}{0}
    {\ifnumgreater{\value{cbx@tempcnta}}{1}
       {\bibrangedash}
       {\multicitedelim}%
     \bibhyperref[\cbx@lastkey]{%
       \ifdef\cbx@lastprefix
         {\printtext[labelprefix]{\cbx@lastprefix}}
         {}%
       \printtext[labelnumber]{\cbx@lastnumber}}}
    {}%
  \setcounter{cbx@tempcnta}{0}%
  \global\undef\cbx@lastprefix}
\makeatother

\addbibresource{\jobname.bib}

\begin{document}\parindent=0pt\relax\parskip=2ex\relax
\nocite{*}

%Cleveland\supercite{fish:drugs:cleveland:use} writes some hard stuff.
Asterix loves fish.\supercite{fish:drugs:evans:intro,fish:drugs:gable:alt,fish:drugs:cleveland:use}

Obelix loves drugs.\supercite{DHS:nik,DHS:alk,DHS:drogen}

Idefix loves Asterix, rotten fish and drugs.\supercite{DHS:nik,DHS:alk,DHS:drogen,A:V1,A:V3,A:V4,A:V5,fish:drugs:evans:intro,fish:drugs:gable:alt,fish:drugs:cleveland:use}

\toggletrue{adapted}

Years ago Idefix loved Asterix, no drugs and good fish.\supercite{DHS:nik,DHS:alk,DHS:drogen,A:V1,A:V3,A:V4,A:V5,fish:drugs:evans:intro,fish:drugs:gable:alt,fish:drugs:cleveland:use} These times have been better\dots

\printbibliography
\end{document}
AndiW
  • 786

1 Answers1

2

Thank you for spotting this. There was a bug in my answer to Biber and Biblatex: reference to multiple subentries. Essentially the issue was that an auxiliary counter was not reset when the labels (labelprefix+labelnumber) were dumped/printed. Since that counter is used to check whether or not to print \multicitedelim, we could get a spurious \multicitedelim in some situations.

The following code should fix that.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[ngerman]{babel}
\usepackage[babel,german=quotes]{csquotes}
\usepackage[backend=biber, style=numeric-comp, mcite, subentry, sortsets=true]{biblatex}
%\usepackage{hyperref}

\makeatletter
% the first two counters are already defined in numeric-comp.cbx
% cbx@tempcnta % no. of labelnumbers we skipped
% cbx@tempcntb % 'predicted' labelnumber for current cite
\newcounter{cbx@tempcntc}% no. of entrysetcounts we skipped
\newcounter{cbx@tempcntd}% 'predicted' entrysetcount
\renewbibmacro*{cite:init}{%
  \global\boolfalse{cbx:parens}%
  \global\undef\cbx@lasthash
  \global\undef\cbx@lastnumber
  \global\undef\cbx@lastprefix
  \global\undef\cbx@lastcount
  \setcounter{cbx@tempcnta}{0}%
  \setcounter{cbx@tempcntb}{-2}%
  \setcounter{cbx@tempcntc}{0}%
  \setcounter{cbx@tempcntd}{-1}}

\newcommand*{\cbx@iflabelnumberequalslast}{%
  \iffieldequals{labelnumber}{\cbx@lastnumber}}

% \iffieldequals is false even if both are empty/undef
% so we need a special test for that case
% this test is optimised for performance and laziness
% rather than prettiness, not that it would matter a lot...
\newcommand*{\cbx@iflabelprefixequalslast}{%
  \ifundef\cbx@lastprefix
    {\iffieldundef{labelprefix}
       {\@firstoftwo}
       {\@secondoftwo}}
    {\iffieldequals{labelprefix}{\cbx@lastprefix}
       {\@firstoftwo}
       {\@secondoftwo}}}

% \cbx@iflabelnumberequalslast and \cbx@iflabelprefixequalslast
\newcommand*{\cbx@iflabelequalslast}{%
  \iffieldequals{labelnumber}{\cbx@lastnumber}
    {\cbx@iflabelprefixequalslast
       {\@firstoftwo}
       {\@secondoftwo}}
    {\@secondoftwo}}

\renewbibmacro*{cite:comp:inset}{%
  \stepcounter{cbx@tempcntd}%
  % the calls for false \cbx@iflabelequalslast
  % are split between stuff that happens before
  % the link and that happens within the link
  \cbx@iflabelequalslast
    {}
    {\usebibmacro{cite:dump}%
     \ifnumgreater{\value{cbx@tempcntb}}{-1}
       {\multicitedelim}
       {}}%
  \printtext[bibhyperref]{%
    \cbx@iflabelequalslast
      {}
      {\setcounter{cbx@tempcntd}{-1}%
       \printfield{labelprefix}%
       \printfield{labelnumber}%
       \savefield{labelprefix}{\cbx@lastprefix}%
       \savefield{labelnumber}{\cbx@lastnumber}}%
    \ifnumequal{\thefield{entrysetcount}}{\value{cbx@tempcntd}}
      {\savefield{entrykey}{\cbx@lastkey}%
       \savefield{entrysetcount}{\cbx@lastcount}%
       \stepcounter{cbx@tempcntc}}
      {\usebibmacro{cite:dump}%
       \ifnumgreater{\value{cbx@tempcntd}}{0}
         {\multicitedelim}
         {}%
       \printfield{entrysetcount}}}%
    \setcounter{cbx@tempcntd}{\thefield{entrysetcount}}%
    \setcounter{cbx@tempcntb}{-1}}

\renewbibmacro*{cite:dump}{%
  % dump subentry
  \ifnumgreater{\value{cbx@tempcntc}}{0}
    {\ifnumgreater{\value{cbx@tempcntc}}{1}
       {\bibrangedash}
       {\multicitedelim}%
     \bibhyperref[\cbx@lastkey]{%
       \printtext[entrysetcount]{\cbx@lastcount}}}
    {}%
  \setcounter{cbx@tempcntc}{0}%
  % dump labelnumber (+labelprefix)
  \ifnumgreater{\value{cbx@tempcnta}}{0}
    {\ifnumgreater{\value{cbx@tempcnta}}{1}
       {\bibrangedash}
       {\multicitedelim}%
     \bibhyperref[\cbx@lastkey]{%
       \ifdef\cbx@lastprefix
         {\printtext[labelprefix]{\cbx@lastprefix}}
         {}%
       \printtext[labelnumber]{\cbx@lastnumber}}%
     \global\undef\cbx@lastprefix}
    {}%
  \setcounter{cbx@tempcnta}{0}}
\makeatother


\usepackage{filecontents}
\begin{filecontents*}{\jobname.bib}
@Book{fish:drugs,
  mainsubtitle = {Drugs and Society},
  year = {2006},
  editor   = {Jefferson M. Fish},
  maintitle= {U.S.~public policy},
  publisher= {Rowman \& Littlefield Publishers, Inc},
  location = {Lanham, Maryland},
  isbn = {0-7425-4245-9},
  sortname = {Jefferson M. Fish},
  sorttitle= {U.S. public policy Drugs and Society},
  options  = {dataonly},
}
@Set{set:fish:drugs,
  entryset = {fish:drugs:gable:alt,fish:drugs:cleveland:use,fish:drugs:evans:intro},
  options  = {multivolumehead=fish:drugs},
}
@Inbook{fish:drugs:evans:intro,
  crossref   = {fish:drugs},
  author = {Richard M. Evans and Stanley Neustadter},
  chapter= {6},
  title  = {Legalization: An Introduction},
  pages  = {129-148},
  sorttitle  = {06 Legalization: An Introduction},
  options= {dataonly},
}
@Inbook{fish:drugs:cleveland:use,
  crossref   = {fish:drugs},
  author = {Mary M. Cleveland},
  chapter= {9a},
  title  = {Use, 'Abuse', Adverse Health Effects, and Addiction},
  pages  = {197-200},
  sorttitle  = {09 Use, Abuse, Adverse Health Effects, and Addiction},
  options= {dataonly},
}
@Inbook{fish:drugs:gable:alt,
  crossref   = {fish:drugs},
  author = {Robert S. Gable},
  chapter= {7},
  title  = {Acute Toxicity of Drugs versus Regulatory Status},
  pages  = {149-161},
  sorttitle  = {07 Acute Toxicity of Drugs versus Regulatory Status},
}
@Book{A,
  author  = {René Goscinny and Albert Uderzo},
  maintitle   = {Asterix und Obelix},
  year    = {1959--2018},
  publisher   = {Dargaud},
  location= {Paris},
  volumes = {99},
  options = {dataonly},
}
@Set{set:A,
  entryset= {A:V1,A:V2,A:V3,A:V4,A:V5,A:V6},
  options = {multivolumehead=A},
}
@Book{A:V1,
  crossref= {A},
  title   = {Asterix der Gallier},
  sorttitle   = {Goscinny Rene Uderzo Albert Asterix und Obelix 01},
  year    = {1959},
  isbn    = {1234567890123},
  volume  = {1},
}
@Book{A:V2,
  crossref= {A},
  title   = {Asterix und Kleopatra},
  sorttitle   = {Goscinny Rene Uderzo Albert Asterix und Obelix 02},
  year    = {1968},
  isbn    = {2345678901234},
  volume  = {2},
}
@Book{A:V3,
  crossref= {A},
  title   = {Asterix als Gladiator},
  sorttitle   = {Goscinny Rene Uderzo Albert Asterix und Obelix 03},
  year    = {1969},
  isbn    = {3456789012345},
  volume  = {3},
}
@Book{A:V4,
  crossref= {A},
  title   = {Der Kampf der Häuptlinge},
  sorttitle   = {Goscinny Rene Uderzo Albert Asterix und Obelix 04},
  year    = {1969},
  isbn    = {4567890123456},
  volume  = {4},
}
@Book{A:V5,
  crossref= {A},
  title   = {Die goldene Sichel},
  sorttitle   = {Goscinny Rene Uderzo Albert Asterix und Obelix 05},
  year    = {1970},
  isbn    = {5678901234567},
  volume  = {5},
}
@Book{A:V6,
  crossref= {A},
  title   = {Tour de France},
  sorttitle   = {Goscinny Rene Uderzo Albert Asterix und Obelix 06},
  year    = {1970},
  isbn    = {6789012345678},
  volume  = {6},
}
@Book{DHS:base,
  editor= {{Deutsche Hauptstelle für Suchtfragen e.~V.}},
  sortname  = {{Deutsche Hauptstelle für Suchtfragen}},
  year  = {2017},
  url   = {www.dhs.de},
  urldate   = {2018-04-30},
  maintitle = {Suchtmedizinische Reihe},
  options   = {dataonly},
}
@Book{DHS:nik,
  crossref  = {DHS:base},
  title = {Tabakabhängigkeit},
  sorttitle = {Deutsche Hauptstelle für Suchtfragen Suchtmedizinische Reihe 01},
  volume= {1},
  isbn  = {978-3-937587-00-4},
}
@Book{DHS:alk,
  crossref  = {DHS:base},
  title = {Alkoholabhängigkeit},
  sorttitle = {Deutsche Hauptstelle für Suchtfragen Suchtmedizinische Reihe 02},
  volume= {2},
  isbn  = {978-3-937587-01-1},
}
@Book{DHS:drogen,
  crossref  = {DHS:base},
  title = {Drogenabhängigkeit},
  sorttitle = {Deutsche Hauptstelle für Suchtfragen Suchtmedizinische Reihe 04},
  volume= {4},
  isbn  = {978-3-937587-03-5},
}
@Set{DHS:SMR,
  crossref  = {DHS:base},
  entryset  = {DHS:alk,DHS:nik,DHS:drogen},
  options   = {multivolumehead=DHS:base},
}
\end{filecontents*}
\addbibresource{\jobname.bib}

\begin{document}
\nocite{*}

%Cleveland\supercite{fish:drugs:cleveland:use} writes some hard stuff.
Asterix loves fish.\supercite{fish:drugs:evans:intro,fish:drugs:gable:alt,fish:drugs:cleveland:use}

Obelix loves drugs.\supercite{DHS:nik,DHS:alk,DHS:drogen}

Idefix loves Asterix, rotten fish and drugs.\supercite{DHS:nik,DHS:alk,DHS:drogen,A:V1,A:V3,A:V4,A:V5,fish:drugs:evans:intro,fish:drugs:gable:alt,fish:drugs:cleveland:use}

Years ago Idefix loved Asterix, no drugs and good fish.\supercite{DHS:nik,DHS:alk,DHS:drogen,A:V1,A:V3,A:V4,A:V5,fish:drugs:evans:intro,fish:drugs:gable:alt,fish:drugs:cleveland:use} These times have been better\dots

Years ago Idefix loved Asterix, no drugs and good fish.\supercite{A:V1,A:V2,A:V3,A:V5} These times have been better\dots

Years ago Idefix loved Asterix, no drugs and good fish.\supercite{A:V3,A:V4,A:V5} These times have been better\dots

Years ago Idefix loved Asterix, no drugs and good fish.\supercite{A:V3,A:V5} These times have been better\dots

\printbibliography
\end{document}

Asterix loves fish. 2a–c//Obelix loves drugs. 1a–c//Idefix loves Asterix, rotten fish and drugs. 1a–c,2a–c,3a,c–e//Years ago Idefix loved Asterix, no drugs and good fish. 1a–c,2a–c,3a,c–e These times have been better...//Years ago Idefix loved Asterix, no drugs and good fish. 3a–c,e These times have been better...//Years ago Idefix loved Asterix, no drugs and good fish. 3c–e These times have been better...//Years ago Idefix loved Asterix, no drugs and good fish. 3c,e These times have been better...

moewe
  • 175,683