[Tex/LaTex] How to emphasize some author names using BibTeX

bibtexemphasis

I would like to create bibliographies that have certain authors highlighted (e.g., bold). There are several solutions along these lines, but they usually assume that it's the same author that's being highlight throughout:

I'm hoping for a BibTeX solution along these lines that lets me indicate, in the .bib file, which authors should be highlighted, e.g.,

author = {J. Doe and J. Smith and J. Quincy}
usera = {1,3}

My goal is to use this for my CV, and to highlight student authors.

Best Answer

My solution works by hacking the bibliography style, similar to what @Katuyci proposed, but conforming more to your example.

  1. Make a copy of your style file. I use plain.bst here, but it works with any other style, too.
  2. Insert usera to the ENTRY field:

    ENTRY {
      ...
      year
      usera      %% added
    }
    
  3. Add the following functions to your style file, after FUNCTION {not} (or after FUNCTION {or} if using natbib). Themultandstr.to.int` functions are taken from Tame the Beast, with a small bug fix.

    INTEGERS {length i a b}
    STRINGS {chr}
    
    FUNCTION {mult}
    {'a :=                  %% we store the first value
     'b :=                  %% we store the second value
     b #0 <                 %% We remember the sign of b, and
        {#-1 #0 b - 'b :=} %% then consider its absolute value.
        {#1}               %%
    if$                    %%
    #0                     %% Put 0 on the stack.
    {b #0 >}               %% While b is strictly positive,
    {                      %% we add a to the value on the stack
        a +                 %% and decrement b.
        b #1 - 'b :=        %%
    }                      %%
    while$                 %%
    swap$                  %% Last, we take the opposite
        'skip$              %% if b was negative.
        {#0 swap$ -}        %%
    if$                    %%
    }
    
    FUNCTION {chr.to.value}        %% The ASCII code of a character
    {
    chr.to.int$ #48 -            %% ASCII value of "0" -> 48
    duplicate$ duplicate$        %%                "1" -> 49
    #0 < swap$ #9 > or           %%                   ...
    {                            %%                "9" -> 57
        #48 + int.to.chr$
        " is not a number..." *
        warning$                %% Return 0 if it is not a number
        #0                      %% here we removed the pop$ before #0,
                                %% opposed to what is written in Tame The Beast
        }
    {}
    if$
    }
    FUNCTION {str.to.int.aux}      %% The auxiliary function
    {
    {duplicate$ empty$ not}      %% While the string is not empty
        {                         %% consider its first char
        swap$ #10 mult 'a :=    %% and ‘‘add’’ it at the end of
        duplicate$ #1 #1 substring$   %% the result.
        chr.to.value a +
        swap$
        #2 global.max$ substring$
        }
    while$
    pop$
    }
    FUNCTION {str.to.int}
    {                              %% Handling negative values
    duplicate$ #1 #1 substring$ "-" =
        {#1 swap$ #2 global.max$ substring$}  %% the first integer here indicates whether we have to
                                            %% multiply by -1, i.e., it is consumed by the following if$
        {#0 swap$}
    if$
                                %% Initialization, and then
    #0 swap$ str.to.int.aux      %% call to the aux. funtion
    swap$
        {#0 swap$ -}              %% And handle the sign.
        {}
    if$
    }
    
    %% takes a string literal from the stack and returns
    %% the position of the first " " (space) in the string;
    %% returns -1 if no space is contained
    FUNCTION {first.space}{
    duplicate$ text.length$ #1 + 'length :=
    #1 'i :=
    { 
        i length <
        { duplicate$ i #1 substring$ 'chr :=
          chr " " =
            { #0 }
            { #1 }
          if$
        }
        {
          #-1
        }
        if$
    }
    { #1 i + 'i := }
    while$
    i length =
        {
          #-1 'i :=
        }
        {}
    if$
    %% finally take the string from the stack
    pop$
    %% space position we identified
    i
    }
    
    %% takes a string literal from the stack,
    %% and returns the first number in the string, and the remaining string;
    %% returns -1 and the original string if no number is found
    STRINGS { tmpstr }
    FUNCTION {chop.number} {
    'tmpstr :=
    tmpstr first.space 'i :=
    i #0 >
        { tmpstr i #1 + global.max$ substring$ %% remaining string
          tmpstr #1 i #1 - substring$ str.to.int    %% number
          duplicate$ #0 =
            { pop$ #-1 }
            {}
          if$
        }
        { "" tmpstr str.to.int
          duplicate$ #0 =
            { pop$ #-1 }
            {}
          if$
        }
    if$
    }
    
  4. Now locate FUNCTION {format.names}, and put

    INTEGERS { hlauthor hlauthorold }
    STRINGS { hlstr }
    

    before that.

  5. format.names has to be modified. I indicated all lines that I added. Your function might look a little different when you are not working with plain.bst, but pretty similar.

    FUNCTION {format.names}
    { 
    's :=
    #1 'nameptr :=
    s num.names$ 'numnames :=
    numnames 'namesleft :=
    usera 'hlstr :=                                          %% added
    hlstr chop.number 'hlauthor := 'hlstr :=                 %% added
      { namesleft #0 > }
      { s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't :=
        nameptr hlauthor =                                   %% added
          {                                                  %% added
            "\hlauthor{" t * "}" * 't :=                     %% added
            hlauthor 'hlauthorold :=                         %% added
            hlstr chop.number 'hlauthor := 'hlstr :=         %% added
            hlauthor #0 >                                    %% added
              { hlauthor hlauthorold >                       %% added
                  {}                                         %% added
                  { "Highlighted authors not sorted for "    %% added
                    cite$ * ": " * hlauthorold int.to.str$ * %% added
                    " >= " * hlauthor int.to.str$ * warning$ %% added
                  }                                          %% added
                if$                                          %% added
              }                                              %% added
              {}                                             %% added
            if$                                              %% added
          }                                                  %% added
          {}                                                 %% added
        if$                                                  %% added
        nameptr #1 >
            { namesleft #1 >
                { ", " * t * }
                { numnames #2 >
                    { "," * }
                    'skip$
                if$
                t "others" =
                    { " et~al." * }
                    { " and " * t * }
                if$
                }
            if$
            }
            't
        if$
        nameptr #1 + 'nameptr :=
        namesleft #1 - 'namesleft :=
        }
    while$
    %% Sanity checks: hlstr should be empty,                 %% added
    %% and hlauthor should be -1                             %% added
    hlstr "" =                                               %% added
      {}                                                     %% added
      { "There are remaining authors to be highlighted for " %% added
        cite$ * ": " * hlstr * warning$                      %% added
      }                                                      %% added
    if$                                                      %% added
    hlauthor #-1 =                                           %% added
      {}                                                     %% added
      { "Unable to highlight author number " hlauthor        %% added
        int.to.str$ * " for " * cite$ * warning$             %% added
      }                                                      %% added
    if$                                                      %% added
    }
    
  6. Finally, we provide a default style for highlighting authors, here we use bold. This is to be injected into the begin.bib function:

    FUNCTION {begin.bib}
    { preamble$ empty$
        'skip$
        { preamble$ write$ newline$ }
      if$
      "\begin{thebibliography}{"  longest.label  * "}" * write$ newline$
      "\providecommand*{\hlauthor}[1]{\textbf{#1}}" write$ newline$   %% added
    }
    

That's it! Let's test it:

\documentclass{article}
\usepackage{filecontents}
\begin{filecontents}{hltest.bib}
@book{a,
  author = {A. First and B. Second and C. Third and D. Forth and E. Fifth and F. Sixth and G. Seventh},
  usera = {1 3 5 4},
  title = {My book title},
  year = 2013,
  publisher = {Inhouse}
}

@book{b,
  author = {A. One and B. Two and C. Three},
  usera = {1 4},
  title = {My book title},
  year = 2013,
  publisher = {Inhouse}
}

@book{c,
  author = {A. Uno and B. Due and C. Tre},
  usera = {4 5},
  title = {My book title},
  year = 2013,
  publisher = {Inhouse}
}

@book{d,
  author = {A. Eins and B. Zwei and C. Drei},
  usera = { 2},
  title = {My book title},
  year = 2013,
  publisher = {Inhouse}
}
\end{filecontents}


\begin{document}
\nocite{*}

% \providecommand{\hlauthor}[1]{\emph{#1}} % if you want to change the style of emphasis
\bibliographystyle{hlplain}
\bibliography{hltest}
\end{document}

sample output

Note that authors to be emphasized should be given in increasing order, e.g.

usera = {10 13 15}, OK
usera = {9 1 2},    NOT OK

separated by spaces. Otherwise you will get warnings as in the test code.