在 biblatex 中压缩集合成员的引用

在 biblatex 中压缩集合成员的引用

@set使用moewe 提供的优秀解决方案压缩会员引用这个问题如果不同集合的成员在一个命令中组合,则会导致压缩机制出现意外行为\cite。显然,内部变化@set无法可靠识别,因此宏会感到困惑。

\toggletrue{adapted}在以下 MWE 中,我实现了对可以通过resp.打开或关闭的集合变化的检查,\togglefalse{adapted}以重现两种变化。

我只是不明白为什么 moewes 解决方案不能按预期工作 - 所以基本上这更像是一个出于好奇的问题......

MWE 的结果是

在此处输入图片描述

其中第 3 行使用原始代码,第 4 行使用改编后的代码。

梅威瑟:

\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}

答案1

谢谢你发现这个问题。我的回答中有一个错误Biber 和 Biblatex:引用多个子条目。本质上,问题是在转储/打印标签 ( labelprefix+ labelnumber) 时辅助计数器未重置。由于该计数器用于检查是否打印,因此在某些情况下\multicitedelim我们可能会得到虚假信息。\multicitedelim

以下代码应该可以修复该问题。

\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}

阿斯特里克斯爱吃鱼。2a–c//Obelix 喜欢毒品。1a–c//Idefix 喜欢阿斯特里克斯、烂鱼和毒品。1a–c,2a–c,3a,c–e//多年以前 Idefix 喜欢阿斯特里克斯、不吃毒品和吃好鱼。1a–c,2a–c,3a,c–e 现在的情况好多了……//多年以前 Idefix 喜欢阿斯特里克斯、不吃毒品和吃好鱼。3a–c,e 现在的情况好多了……//多年以前 Idefix 喜欢阿斯特里克斯、不吃毒品和吃好鱼。3c–e 现在的情况好多了……//多年以前 Idefix 喜欢阿斯特里克斯、不吃毒品和吃好鱼。3c,e 现在的情况好多了……

相关内容