1

I would like to split the output of \mkcomprange using \StrBefore (or vice-versa, or something else equivalent), but neither ordering seems to work.

  1. Desired output: 23-24;34-35 becomes 23–24.

  2. Output of \mkcomprange{\StrBefore{23-24;34-35}{;}} is 23-24.

  3. Output of \StrBefore{\mkcomprange{23-24;34-35}{,}} is blank.

I'm guessing the output of #3 is because \mkcomprange doesn't output a literal comma, but I can't figure out why #2 doesn't work, whereas \mkcomprange{23-24} outputs 23–24 as expected. I should note that this is all in the context of biblatex-chicago.


For broader context: I'm working on a custom biblatex entry type that requires that I parse two distinct sets of page numbers out of the postnote and print them in two distinct places in the citation. The first set is the cited document's own internal paragraph numbering, whereas the second is the pages of the particular printed edition being used. For example, I would like \autocite[23-24;34-35]{doc} to output 'Author, Document Title 23–24: Book Title (Place: Publisher, 2020) 34–35'. I have all the other pieces in place, but I haven't been able to figure out how to get the two different numbering schemes to work.

My current setup looks roughly like this:

\DeclareFieldFormat{postnote:first}{%
    \mkcomprange{\StrBefore{#1}{;}}%
}
\DeclareFieldFormat{postnote:second}{...}
\printfield[postnote:first]{postnote}
\printfield[postnote:second]{postnote}
1
  • Can you please provide a minimal working example, in which the packages providing commands \mkcomparerange and \StrBefore are loaded? Mar 13, 2020 at 2:52

1 Answer 1

4

This is an expandability issue paired with the fact that string manipulation is hard in TeX.

Essentially biblatex's \mkcomprange{<text>} only works as advertised if its argument <text> is a literal string. If the argument is too complex to be parsed correctly by \mkcomprange, \mkcomprange will simply do nothing. Not even

\newcommand\foo{23-24;34-35}
\mkcomprange{\foo}

works as one might hope, since \foo is not a string (it is a macro expanding to a string).

In

\mkcomprange{\StrBefore{23-24;34-35}{;}}

\mkcomprange does nothing, because its argument is too complex and only \StrBefore does its thing, leaving us with

23-24

and not the desired

23\bibrangedash 4

Coming back to the \foo example from above, the following works

\newcommand\foo{23-24;34-35}
\expandafter\mkcomprange\expandafter{\foo}

because the \expandafters make sure to expand \foo first before \mkcomprange sees it, so that \mkcomprange is not called with the argument \foo (which doesn't do the right thing, see above) but with 23-24;34-35 (which works).

Thinking further along those lines, one might try

\expandafter\mkcomprange\expandafter{\StrBefore{23-24;34-35}{;}}

Unfortunately, that fails spectacularly with all kinds of error messages. The problem here is that the command \StrBefore is not expandable, which means that it can not be massaged with commands like \expandafter (or in an \edef context) to just reveal the string directly.

The developer of xstring implemented a way of working around that: You can let \StrBefore write its output to a macro and use that. So the following again works

\StrBefore{23-24;34-35}{;}[\AVBtemp]
\expandafter\mkcomprange\expandafter{\AVBtemp}

For your simple requirements, you don't need xtstring at all. You can build something that splits your postnote at the ; yourself.

\documentclass[british]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage{csquotes}

\usepackage[style=authoryear, backend=biber]{biblatex}

\addbibresource{biblatex-examples.bib}

\makeatletter
\newcommand*{\AVBpostnotesplitcompOne}[1]{\AVBpostnotesplitcompOne@i #1;\relax}
\def\AVBpostnotesplitcompOne@i#1;#2\relax{%
 \ifblank{#2}
   {\mkcomprange{#1}}
   {\AVBpostnotesplitcompOne@ii #1;#2\relax}}
\def\AVBpostnotesplitcompOne@ii#1;#2;\relax{\mkcomprange{#1}}

\newcommand*{\AVBpostnotesplitcompTwo}[1]{\AVBpostnotesplitcompTwo@i #1;\relax}
\def\AVBpostnotesplitcompTwo@i#1;#2\relax{%
 \ifblank{#2}
   {}
   {\AVBpostnotesplitcompTwo@ii #1;#2\relax}}
\def\AVBpostnotesplitcompTwo@ii#1;#2;\relax{\mkcomprange{#2}}
\makeatother


\begin{document}
\AVBpostnotesplitcompOne{Hallo}|\AVBpostnotesplitcompTwo{Hallo}

\AVBpostnotesplitcompOne{23-24;35-36}|\AVBpostnotesplitcompTwo{23-24;35-36}

\AVBpostnotesplitcompOne{23-24;}|\AVBpostnotesplitcompTwo{23-24;}

\AVBpostnotesplitcompOne{;35-36}|\AVBpostnotesplitcompTwo{;35-36}

\AVBpostnotesplitcompOne{23-24;35-36;46-45}|\AVBpostnotesplitcompTwo{23-24;35-36;46-45}

\cite{sigfridsson}
\printbibliography
\end{document}

Hallo|//23–4|35–6//23–4|//|35–6//23–4|35–6, 46–5


\StrBefore{\mkcomprange{23-24;34-35}}{,}

doesn't work because because \mkcomprange is not expandable and so \StrBefore performs its actions on \mkcomprange{23-24;34-35}, where there is no comma to be found.


You may also be interested in Optional argument within another optional argument in biblatex \cite, where Audrey shows a way to split the argument structure of the postnote into different subarguments.

5
  • The \expandafter solution works fine for my needs (I'm happy to keep xstring in favour of more readable code), but thank you for the alternatives as well. Thank you also for the explanation; I'll keep that in mind while debugging in the future.
    – AVB
    Mar 13, 2020 at 13:27
  • As it turns out, the solution without xstring is more stable. Some of the citations include § (so something like §14;17-18), and the xstring solution choked on that.
    – AVB
    Mar 13, 2020 at 18:50
  • moewe, may I (ab)use this for a ping on a related issue? (I tried the chat first, but no completion of your handle there...) Do you happen to know why maxcomprange exists? What is the reason to impose an upper limit beyond which compression no longer occurs?
    – gusbrs
    Feb 3, 2022 at 19:19
  • @gusbrs Sorry, absolutely no idea. Maybe for symmetry reasons? Maybe someone requested it.
    – moewe
    Feb 3, 2022 at 20:00
  • @moewe It got me curious, I'm looking into implementing similar functionality for page cross-references and, naturally, biblatex was the first place I looked. And I could not find a reason for it to exist, thus the question. Thanks for answering!
    – gusbrs
    Feb 3, 2022 at 20:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .