The principles of the punctuation buffer and its workings are really rather simplistic. To understand why you get the result you get, the following should be sufficient (more details and examples can be found in the already linked What do \setunit and \newunit do? and biblatex: \DeclareCiteCommand adds semicolon between \printfield and \printnames, but only sometimes)
\setunit{<punctuation>} (for all intents and purposes \newunit is just \setunit{\newunitpunct}) puts <punctuation> into the punctuation buffer. If the buffer already contains a value, that value is overwritten (unless the previous value was added to the buffer with \printunit, \printunit persists in the buffer and cannot be overwritten).
The punctuation buffer is printed out and emptied whenever a \printfield (\printlist, \printnames, \printtext) prints something provided that anything has been printed at all (for biblatex punctuation is between two elements, so there is no point in printing punctuation before anything has been printed).
The current value remains in the buffer until it is overwritten by a \setunit or printed out between two \print... commands.
So now to
\printfield{title}%
\newunit%
\printtext{word}%
\printtext{string}%
\usebibmacro{finentry}%
If the title is non-empty, everything works as expected.
\printtext{title} prints the title and tells the punctuation buffer that something was printed.
\newunit puts \newunitpunct in the punctuation buffer.
\printtext{word} prints the punctuation (and empties the buffer) and then "word".
\printtext{string} prints "string".
Because the punctuation buffer is empty after \printtext{word}, there is no punctuation between "word" and "string".
If the title is empty, here is what happens.
- Nothing is printed by
\printtext{title}.
\newunit puts \newunitpunct in the punctuation buffer.
\printtext{word} prints "word", but does not print any punctuation, because nothing was printed before. The buffer still contains \newunitpunct.
\printtext{string} prints the punctuation, empties the buffer and then prints "string".
There are several ways to deal with the issue in this example, but depending on your actual use case some of these options might be preferable over others.
- A simple solution is to move
\printtext{word} and \printtext{string} into the same \printtext{wordstring}.
- You could empty the punctuation buffer explicitly yourself with
\setunit{} between \printtext{word} and \printtext{strgin} as suggested by Ulrike Fischer in the comments.
- You can use the starred
\setunit* instead of \setunit/\newunit after \printfield{title}, which only adds punctuation to the buffer if the previous command printed anything. (See Is there any difference between \setunit*{<punct>} and \setunit{\add<punct>} for a discussion of \setunit vs \setunit*.)
The following MWE shows these three ideas.
\documentclass{article}
\usepackage[backend=biber]{biblatex}
\DeclareBibliographyDriver{article}{%
\printfield{title}%
\newunit
\printtext{wordstring}%
\usebibmacro{finentry}%
}
\DeclareBibliographyDriver{book}{%
\printfield{title}%
\newunit
\printtext{word}%
\setunit{}%
\printtext{string}%
\usebibmacro{finentry}%
}
\DeclareBibliographyDriver{incollection}{%
\printfield{title}%
\setunit*{\newunitpunct}%
\printtext{word}%
\printtext{string}%
\usebibmacro{finentry}%
}
\begin{filecontents}{\jobname.bib}
@article{art:WithTitle,
title = {Testtext},
presort = {a},
}
@article{art:WithoutTitle,
title = {},
presort = {b},
}
@book{book:WithTitle,
title = {Testtext},
presort = {c},
}
@book{book:WithoutTitle,
title = {},
presort = {d},
}
@incollection{incoll:WithTitle,
title = {Testtext},
presort = {e},
}
@incollection{incoll:WithoutTitle,
title = {},
presort = {f},
}
\end{filecontents}
\addbibresource{\jobname.bib}
\begin{document}
\nocite{*}
\printbibliography
\end{document}
![[1] “Testtext”. wordstring.
[2] wordstring.
[3] Testtext. wordstring.
[4] wordstring.
[5] “Testtext”. wordstring.
[6] wordstring.](../../images/8a179e8eb343c602db69e53f365ff52e.webp)