7

I have a question about manipulating a bst file to remove a period after a middle initial. Assume the following .bib file entry:

@BOOK{author1999book,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {First M. Last},
}

I've been working with the apa.bst file on some various hacks to create a bst file that speaks well with a particular journal. One of the things they demand is that middle initials do not have periods after them. Thus, their style for the bibliography section looks like:

Last, First M (1999) Very informative and handsome book. College Town, ST: College University Press.

I already modified the apa.bst file to address the other peculiarities of formatting (parentheses around the years, capitalization of titles). What's left is the issue of periods after middle initials.

Now, I can get this by simply removing the period after the middle initial in the .bib file entry. What I would like to do, though, is find a way to do that in the *.bst file. Can I? The reason I ask is that several bst styles will actually include that period if it's not there in the *.bib file. What I would like to do is get the bst file to remove the period from the middle initial if it is there in the *.bib file. I didn't know if that was possible and, if so, how I could do it.

  • 1
    Just pick the first letter of the middle name. This will work also if the bib fully specifies the name. – JLDiaz Jul 3 '13 at 20:59
  • How would one do that in, for example, the apa.bst file? Again, thanks for any input. – guest Jul 3 '13 at 21:27
6

The function which format the list of names inside the bst file is the one called format.names. For example, for the apa.bst file, this function has the following code:

FUNCTION {format.names}
{ 's :=
  #1 'nameptr :=
  s num.names$ 'numnames :=
  numnames 'namesleft :=
    { namesleft #0 > }
    { s nameptr "{vv~}{ll}{, jj}{, f.}" format.name$ 't :=   % last name first
      nameptr #1 >
  [... etc ...]
}

For full details about the syntax used in bst files and in this function in particular, refer to the document Taming the beast (pag. 35).

The line which we have to modify in this case is the one containing the string:

"{vv~}{ll}{, jj}{, f.}"

This string specifies the required format for the name of each author. vv represents the "von" part (if it exists) ll is the full last name, jj is the "junior" part of the name (if it exists) and finally ff would be the full first name, while f is the initial of the first name. Commas and dots are literals and are added in the output.

Removing the dot after the f produces the result you want, or almost:

Almost

Note that, since we used f instead of ff, both the first and middle names are abbreviated. But using ff we will have both expanded. Apparently BibTeX does not have a notion of "middle name", all what is not last name is considered first name.

If you need the first name "fully expanded" but the middle name abbreviated and without dot, then this is beyond my bibtex abilities. I don't even know if that would be possible.

  • Yeah, having a full first name with middle name abbreviation (without a dot) is kind of what I was hoping to learn. But, if that's beyond BibTex's capabilities, then I guess that's that. I do appreciate your help. – guest Jul 4 '13 at 6:22
  • well it is possible as stated by Steven B. Segletes in his answer below. This comment might be helpful for people giving up too early... – tc88 Jul 13 '18 at 17:54
3

I was showing a colleague my original answer (below), and he found a pathological case. I should point out that our particular application is for abbreviated first and middle names (which is not exactly the same as the OP asks, but a common enough need).

He said to me, "you know, there is an easy way to fix this." Edit the .bst file where the name is parsed (it will look something like nameptr "{ff~}{vv~}{ll}{, jj}") and change the first name field (with the f) to {f{}~} (or {f{}} if it is the last item to appear in the author field).

How easy is that?! And it worked like a champ for our application. And while it isn't exactly the OP's query, I thought it useful enough that I wanted to list it here on the site, for others who have need of tailoring author fields.

UPDATE: I have since learned that this trick is provided by Oren Patashnik on the last paragraph of his document"BibTeXing", found at http://bibtexml.sourceforge.net/btxdoc.pdf.

Changing that one line in plain.bst makes the following MWE (same as in my original answer):

\documentclass{article}
\usepackage{filecontents}
\begin{filecontents}{mybib.bib}
@BOOK{author1999book,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {First M. Last},
}
@BOOK{test2,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {Last, First M.},
}
@BOOK{test3,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {Last, F. M.},
}
\end{filecontents}
\bibliographystyle{plain}

%%BibTeX Dot Removal Macro
\let\svdot. % CAN SAVE THE DOT IF NEEDED SOMEWHERE IN AUTHOR LIST
\catcode`.=\active
\def\NoBibDots#1{\let.\relax#1\catcode`.=12}
% THE FOLLOWING LINE WOULD BE USEFUL FOR "Last FM, ..." FORMATS
%\def\NoBibDots#1{\def~{ }\let.\ignorespaces#1\catcode`.=12}
\catcode`.=12
\begin{document}
Citing\cite{author1999book,test2,test3}
\bibliography{mybib}
\end{document}

produce this output

enter image description here

ORIGINAL ANSWER:

I was stewing over this question for some time (since last July) trying to parse the authors to remove dots and met with glitches and quirks. But then I came up with a different idea of making . active to remove it. It will actually remove every dot from the author list (which can be countermanded by using \svdot{} in your bib entry).

In this MWE, I use plain.bst, but have verified the approach works (perhaps with some tuning) for other configurations. I provide commented code for using with bst files that use a LAST FM approach (see apalike example at the end of this post). To prepare the bst file, add this macro:

FUNCTION {no.bib.dots}
{ duplicate$ empty$
    { pop$ "" }
    { "\catcode`.=\active\NoBibDots{" swap$ * "}\catcode`.=12" * }
  if$
}

and modify this standard one:

FUNCTION {format.authors}
{ author empty$
    { "" }
%    { author format.names }% THIS WAS THE ORIGINAL LINE REPLACED BELOW
     { author format.names no.bib.dots "." * }
  if$
}

Note that

{ author format.names no.bib.dots "." * }

could be replaced with

{ author format.names no.bib.dots "~" * }

if you wanted a trailing space instead of a period, or simply with

{ author format.names no.bib.dots }

for neither space nor period. Then, in your document, style, or class, define \NoBibDots as follows:

%%BibTeX Dot Removal Macro
\let\svdot. % CAN SAVE THE DOT IF NEEDED SOMEWHERE IN AUTHOR LIST
\catcode`.=\active
\def\NoBibDots#1{\let.\relax#1\catcode`.=12}
% THE FOLLOWING LINE WOULD BE USEFUL FOR "Last FM, ..." FORMATS
%\def\NoBibDots#1{\def~{ }\let.\ignorespaces#1\catcode`.=12}
\catcode`.=12

Here is the full MWE and the associated result:

\documentclass{article}
\usepackage{filecontents}
\begin{filecontents}{mybib.bib}
@BOOK{author1999book,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {First M. Last},
}
@BOOK{test2,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {Last, First M.},
}
@BOOK{test3,
title = {Very Informative and Handsome Book},
publisher = {College Town, ST: College University Press},
year = {1999},
author = {Last, F. M.},
}
\end{filecontents}
\bibliographystyle{plain}

%%BibTeX Dot Removal Macro
\let\svdot. % CAN SAVE THE DOT IF NEEDED SOMEWHERE IN AUTHOR LIST
\catcode`.=\active
\def\NoBibDots#1{\let.\relax#1\catcode`.=12}
% THE FOLLOWING LINE WOULD BE USEFUL FOR "Last FM, ..." FORMATS
%\def\NoBibDots#1{\def~{ }\let.\ignorespaces#1\catcode`.=12}
\catcode`.=12
\begin{document}
Citing\cite{author1999book,test2,test3}
\bibliography{mybib}
\end{document}

enter image description here


To demonstrate the flexibility for other bst styles, I made the identical changes to apalike.bst as described above for plain.bst. apalike has a "Last, F. M." format that I would like to represent instead as "Last, FM.". The following MWE, in which I redefined \NoBibDots to absorb spaces following the removal of dots, gives the associated result:

\documentclass{article}
\usepackage{filecontents}
\begin{filecontents}{junk.bib}
@ARTICLE{bake67,
        TITLE   = "Prediction and scaling of reflected impulse from
                        strong blast waves",
        AUTHOR  = "Baker, W. E.",
        JOURNAL = "International Journal of Mechanical Sciences",
        VOLUME  = "9",
        NUMBER  = "1",
        PAGES   = "45--51",
        YEAR    = "1967"                        }
@ARTICLE{Acme72,
        TITLE   = "Prediction and scaling of reflected impulse from
                        strong blast waves",
        AUTHOR  = "Acme, Wesley E.",
        JOURNAL = "International Journal of Mechanical Sciences",
        VOLUME  = "9",
        NUMBER  = "1",
        PAGES   = "45--51",
        YEAR    = "1972"                        }
@ARTICLE{cake71,
        TITLE   = "Prediction and scaling of reflected impulse from
                        strong blast waves",
        AUTHOR  = "Cake, Wesley Excaliber",
        JOURNAL = "International Journal of Mechanical Sciences",
        VOLUME  = "9",
        NUMBER  = "1",
        PAGES   = "45--51",
        YEAR    = "1971"                        }
@ARTICLE{Delta71,
        TITLE   = "Prediction and scaling of reflected impulse from
                        strong blast waves",
        AUTHOR  = "Delta, W. Excaliber",
        JOURNAL = "International Journal of Mechanical Sciences",
        VOLUME  = "9",
        NUMBER  = "1",
        PAGES   = "45--51",
        YEAR    = "1971"                        }
\end{filecontents}
%%BibTeX Dot Removal Macro
\let\svdot. % CAN SAVE THE DOT IF NEEDED SOMEWHERE IN AUTHOR LIST
\catcode`.=\active
%\def\NoBibDots#1{\let.\relax#1\catcode`.=12}
% THE FOLLOWING LINE WOULD BE USEFUL FOR "Last FM, ..." FORMATS
\def\NoBibDots#1{\def~{ }\let.\ignorespaces#1\catcode`.=12}
\catcode`.=12
\begin{document}
cite \cite{bake67, Acme72, cake71, Delta71}
\bibliographystyle{apalike}
\bibliography{junk}
\end{document}

enter image description here

2

After studying bst syntax a bit deeper, I was finally able to code a solution. My "simple hack" turned out being not so simple, so I think that it deserves a new and detailed answer.

My idea was to use the format.name$ function with the format "{ff}" to extract only the first name (which would be "First Medium" in your example), and then use again format.name$ over this result, with the string "{ff}{ l}" to get "First M" as required.

But then I tried to cover other possibilities in which that simple hack would fail, such as authors without middle name, or even without first name (only last name provided). Since the code for detecting and dealing such cases started to be too complex, I wrote a specific function to do all this, and then I call that function from the main formatting authors function.

The new function is called format.trick and expects a string in the top of the stack containing a single author name (for example "First Medium Last", accepting also the notation "Last, First Medium". This function leaves on top of the stack the "normalized" name, which will be "Last, First M". It correctly deals with authors without medium name or without first name. This is the heavily commented code of this function:

STRINGS {ss tt fm}
FUNCTION {format.trick}
{
    'ss :=   %% Make a copy of the name in s
    %% Extract the First (and possible Medium) names
    %% and store it in variable fm
    ss #1 "{ff}" format.name$ 'fm :=

    %% Note that now fm could contain:
    %% * An empty string ("") if the author has no first name (only Last name was provided)
    %% * A single word (like "First") if the author has no medium name
    %% * A sequence of words (like "First Medium")
    %% For the last case we want to abbreviate "Medium", without dot

    %% Test if we are in the first case
    fm empty$ {
       % If empty (no first name), use the standard formatting
       ss #1 "{vv~}{ll}{, jj}{, ff}" format.name$
    }{ % Otherwise, attempt the trick
        %% Now the trick. Interpret "First Medium"
        %% as if "Medium" were a last name, and abbreviate it
        fm #1 "{ff }{l}" format.name$ 'tt :=   %% And store the result in tt
        %% Consider the particular case in which no Medium name is present
        %% In this case, "First" will be interpreted as a last name, and
        %% thus abbreviated. This can be detected because the resulting
        %% string has length 1
        tt text.length$ #1 > { %% If there was a medium name
            tt  %% Store the abbreviated version
            }{  %% Else store the original version of the name
            fm
            } if$

        %% After the above, the top of the stack will contain
        %% either "First" unabbreviated (if the author has not middle name)
        %% or "First M", as required
        'tt :=  %% Copy that value to tt

        %% Now complete the standard formatting of the author, omitting
        %% the first name part, which is stored in tt
        ss #1 "{vv~}{ll}{, jj}" format.name$
        %% And concatenate to it the value of tt
        ", " *
        tt *
  }if$   %% If the trick has to be done
}

You can insert that code anywhere in the bst, before format.names function, and then you modify also format.names function, changing the line:

    { s nameptr "{vv~}{ll}{, jj}{, ff}" format.name$ 't :=

to

    { s nameptr "{vv~}{ll}{, jj}{, f}" format.name$
      % Postprocess result
      format.trick 't :=

I tried the new .bst with a bib including a complex author list:

@BOOK{author1999book,
    title = {Very Informative and Handsome Book},
    publisher = {College Town, ST: College University Press},
    year = {1999},
    author = {
          Last, First Middle
      and Lastonly
      and Last2, First2 M.
      and Last3, First3 M
      and Last4, Firstonly
    }
}

It worked as expected:

Result

It was fun to wrap my head around the stack-based bst language. :-)

Update

The OP used a bst style a bit more convoluted, in which the first author is formatted differently to the remaining authors. This makes my above trick not directly useable. The OP provided me the complete bst and I was able to find what lines to modify to accomodate the above trick.

The functions format.authors and format.rem.authors (which produce the format for the first author and the remaining ones, respectively) have to be modified like this (although only two lines need change, I prefer to paste the complete functions):

FUNCTION {format.rem.names}
{ 's :=
  'f :=
  #2 'nameptr :=
  s num.names$ 'numnames :=
  numnames #1 - 'namesleft :=
    { namesleft #0 > }
    { s nameptr f format.name$   % <-----
      format.trick               % <-----
      #1 f format.name$ 't :=    % <-----
      nameptr #1 >
    { namesleft #1 >
        { "; " * t * }
        { t "others" =
        { " et~al." * }
        { "  \& " * t * }
          if$
        }
      if$
    }
    't
      if$
      nameptr #1 + 'nameptr :=
      namesleft #1 - 'namesleft :=
    }
  while$
}

FUNCTION {format.authors}
{ author empty$
    { "" }
    { author #1 "{vv~}{ll}{, jj}{, ff}" format.name$
      format.trick                                     %% <----
      #1 "{vv~}{ll}{, jj}{, ff}" format.name$          %% <----
      "{ff }{vv~}{ll}{, jj}" author format.rem.names
    }
  if$
}

The code of the function format.trick is the same than the one I gave in the original answer, above.

With these changes, the bibliography entry looks like this:

Result

Note how the first author is "Last, First", while the remaining ones are "First Last", and in all cases the middle name is abbreviated without dot. I guess this is the desired output.

  • 1
    Neat trick! But Lennon, John Winston Ono comes out as Lennon, John Winston O, right? I.e., the abbreviate-middle-name-as-last-name-of-firstnamelist trick picks up only the last middle name for abbreviation? +1 Anyway. – mafp Jul 4 '13 at 15:25
  • @mafp Yes you are right. Not sure of what would be an acceptable outcome for this case, though. – JLDiaz Jul 4 '13 at 15:49
  • Very neat trick. It worked like a charm in the simplified example I asked for, but not the more complicated actual *.bst file that I'm working with. Most of the action is happening here in the format.authors field, actually mostly derived from the newapa.bst file. My apologies for the confusion: FUNCTION {format.authors} { author empty$ { "" } { author #1 "{vv~}{ll}{, jj}{, ff}" format.name$ "{ff }{vv~}{ll}{, jj}" author format.rem.names } if$ } Any input is very much appreciated and I thank you all for your time. – guest Jul 4 '13 at 18:44
  • @JLDiaz: You're right. I added that. I didn't know how complicated of a job this would be, so I thought minimal information would be sufficient at first. Here is the hack of a newapa.bst file I've been working with. Everything in here is exactly how I want it. I'm just hoping to find a solution for the issue of middle initials. pastebin.com/jcPtdN3J Thanks again for your continued help. It means a lot. – guest Jul 5 '13 at 16:02
  • A corollary question might be if there's a way to (for lack of better term) "grep" out periods after middle initials from the *.tex document. The solution I'm looking for would ideally leave the *.bib file untouched, but format the references through either the *.bst file or the *.tex file. – guest Jul 5 '13 at 16:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.