Here is another attempt based on @moewe's solution. It should fix some of the problems discovered in comments.
It does not fix the issue with accented letters. I have no idea why they do not get parsed properly into the given-i
field [Fix in edit below].
MWE
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents}{\jobname.bib}
@book{Book1,
author = {Savigny, Friedrich Carl von},
title = {An Important Book},
publisher = {Publisher},
date = {2012},
}
@book{Book2,
author = {de La Vaissière, Claude-Henri},
title = {Another Important Book},
publisher = {Publisher},
date = {2014},
}
@book{Book3,
author = {Durand, Jean-Philippe},
title = {A very Important Book},
publisher = {Publisher},
date = {2016},
}
@book{Book4,
author = {de La Boétie, Étienne},
title = {A very Important Book},
publisher = {Publisher},
date = {2016},
}
@book{Book5,
author = {Doe, Charles-Édouard},
title = {A very Important Book},
publisher = {Publisher},
date = {2016},
}
@book{Book6,
author = {Dolittle, Étienne-Marie},
title = {A very Important Book},
publisher = {Publisher},
date = {2016},
}
\end{filecontents}
\usepackage[style=verbose,giveninits=true, backend=biber]{biblatex}
\addbibresource{\jobname.bib}
\makeatletter
\def\do#1{%
\ifcsundef{blx@csv@datamodel@names}
{\csdef{blx@csv@datamodel@names}{#1}}
{\csappto{blx@csv@datamodel@names}{,#1}}}
\dolistcsloop{blx@datamodel@names}
\DeclareSourcemap{
\maps[datatype=bibtex]{
\map[foreach=\blx@csv@datamodel@names]{
\step[fieldsource=\regexp{$MAPLOOP},
match=\regexp{(\A|\s+and\s+)([a-z'\s]+)?\s*(.+?)\,\s+(Chr?|Th|Ph|[B-DF-HJ-NP-TV-XZ](?:l|r)|\w(?=\w+-))([\w\s]+)(?:(-)(Chr?|Th|Ph|[B-DF-HJ-NP-TV-XZ](?:l|r)|\w)([\w\s]+))?(?=\Z|\s+and\s+)},
replace=\regexp{$1 family=$3, prefix=$2, given=$4$5$6$7$8, given-i=\{$4$6$7\}}]
\step[fieldsource=\regexp{$MAPLOOP},
match=\regexp{(prefix=\,)},
replace=\regexp{}]
}
}
}
\makeatother
\begin{document}
Friedrich Carl von Savigny:\par
\cite{Book1}\medskip
Claude-Henri de La Vaissière:\par
\cite{Book2}\medskip
Jean-Philippe Durand:\par
\cite{Book3}\medskip
Étienne de La Boétie:\par
\cite{Book4}\medskip
Charles-Édouard Doe:\par
\cite{Book5}\medskip
Étienne-Marie Dolittle:\par
\cite{Book6}
\end{document}

As can be noted from the output above:
- Names with
von
parts work properly (no support for Jr
parts).
- When a person has several first names, only the first one gets abbreviated (this is common practice when using several initial letters for a single name).
- When a person has a composed name, including a hyphen, both parts of the name are properly abbreviated.
And, as a workaround for the [now solved] problem with accented letters, the regexp I use tries to minimise the number of cases in which we will use extended name format, so as to preserve native parsing of names (and the accented letters). At the moment, it means that:
- Single or multiple first names starting with an accented letter will keep it
- Accented initials in composed names will be converted to the non-accented version, as shown in the sample above.
Here is the detailed code, largely inspired from @moewe:
\def\do#1{%
\ifcsundef{blx@csv@datamodel@names}
{\csdef{blx@csv@datamodel@names}{#1}}
{\csappto{blx@csv@datamodel@names}{,#1}}}
\dolistcsloop{blx@datamodel@names}
\DeclareSourcemap{
\maps[datatype=bibtex]{
\map[foreach=\blx@csv@datamodel@names]{
\step[fieldsource=\regexp{$MAPLOOP},
match=\regexp{(\A|\s+and\s+)([a-z'\s]+)?\s*(.+?)\,\s+(Chr?|Th|Ph|[B-DF-HJ-NP-TV-XZ](?:l|r)|\w(?=\w+-))([\w\s]+)(?:(-)(Chr?|Th|Ph|[B-DF-HJ-NP-TV-XZ](?:l|r)|\w)([\w\s]+))?(?=\Z|\s+and\s+)},
replace=\regexp{$1 family=$3, prefix=$2, given=$4$5$6$7$8, given-i=\{$4$6$7\}}]
\step[fieldsource=\regexp{$MAPLOOP},
match=\regexp{(prefix=\,)},
replace=\regexp{}]
}
}
}
Stripping it down, in case someone else wants to toy with the regexp:
(\A|\s+and\s+)
: Look for name boundaries ("and" is the separator). Matches $1
.
([a-z'\s]+)?
: Look for the von
part, which only interests us when it is lowecased (as it will influence sorting). Matches $2
.
\s*(.+?)\,\s+
: Look for the last name, followed by a comma. Matches $3
.
(Chr?|Th|Ph|[B-DF-HJ-NP-TV-XZ](?:l|r)|\w(?=\w+-))
: Look for the strings that should be used as inits in the first name, or alternatively, take the first letter (\w
), but only if the first name is composite (look ahead for \w+-
, i.e. letters followed by a hyphen). This allows us to exclude some accented initials from the test, so as to preserve them. Matches $4
.
([\w\s]+)
: Look for the rest of the first name, including any subsequent first names. Matches $5
.
(?:(-)(Chr?|Th|Ph|[B-DF-HJ-NP-TV-XZ](?:l|r)|\w)([\w\s]+))?
: In case the name is a composite one, repeat the last two steps, but look for a starting hyphen (matches $6
), then the initial string or letter (matches $7
, no need to look ahead here), then the rest of the first name (matches $8
).
(?=\Z|\s+and\s+)
: Look ahead for name boundaries = end.
Also, biber
issues warnings when given a an empty von
part. Hence, we need a second step to look for prefix=\,
and clear it.
Edit: In the comments below, @andc discovered a bug in the above code and, while I do not have time to investigate it properly, I do have a newer version of the code that does not have this bug. As a bonus, this edit also solves the previous problem with accented first letters.
Here is the code:
\def\do#1{%
\ifcsundef{blx@csv@datamodel@names}
{\csdef{blx@csv@datamodel@names}{#1}}
{\csappto{blx@csv@datamodel@names}{,#1}}}
\dolistcsloop{blx@datamodel@names}
\map[foreach=\blx@csv@datamodel@names,overwrite=true]{%
\step[fieldsource=\regexp{$MAPLOOP},%
match=\regexp{(\A|\s+and\s+)([a-z'\s]+)?\s*(.+?)\,\s+(Chr?|Th|Ph|[B-DF-HJ-NP-TV-XZ](?:l|r)|(?:À|Â|Ä|Ç|É|È|Ê|Ë|Î|Ï|Ô|Ö|Ù|Û|Ü|Ÿ|Æ|Œ)|\w)(.+?)(?:(\-(?:Chr?|Th|Ph|[B-DF-HJ-NP-TV-XZ](?:l|r)|(?:À|Â|Ä|Ç|É|È|Ê|Ë|Î|Ï|Ô|Ö|Ù|Û|Ü|Ÿ|Æ|Œ)|\w))(.+?))?(?=\Z|\s+and\s+)},
replace=\regexp{$1 family=$3, prefix=$2\\relax, given=$4$5$6$7, given-i=\{$4$6\}}]
\step[fieldsource=\regexp{$MAPLOOP},
match=\regexp{(prefix=\,)},
replace=\regexp{}]
}
\"A
without conversion to UTF-8, for example) is basically a hard/impossible problem in general without slow state parsing. So, I have to concentrate on UTF-8 conversion and not stripping arbitrary macro constructions. @moewe's solution is the best idea.bibtex
backend instead of the default biber (i.e.backend=bibtex
option to the package). Then\relax
will work, but the functionality of biblatex will be limited. Check the biblatex documentation, section 3.15, to see what are the specific limitations (I don't have a very good understanding of this topic).