Pybtex: Pythonで書くBibTeXのスタイルカスタマイズ

## Abstract

[Pybtex](https://pybtex.org)とは、Pythonで書かれた、BibTeXに互換性を持つbibliographyプロセッサーです。
しかしながら、「そもそもPythonでわざわざBibtexの処理を置き換える必要があるのか？」となりますよね。
大きなメリットとして、「**Pythonでスタイルをカスタマイズできる**」という点が挙げられます。というのも、Bibtexはスタイルのカスタマイズには独自のbstファイルを書く必要があります。これを馴染みのあるPythonで書くことができるのはかなり良い点と感じます。
この記事では、[Pybtex](https://pybtex.org)のプラグイン(ドキュメントですら情報がほとんどない...)を用いてスタイルをカスタマイズする実装例を紹介します。

## 前提知識 / 注意事項

- Latex, Bibtex自体の知識
- Pythonの文法
    - `class`がわかればよいですが、更なるカスタマイズにはデコレータなどを含む複雑なコードを読み解く必要あり

なお筆者の環境はWindows 10 / Python 3.10.xです。
また本記事では、どちらかと言えばスタイルのカスタマイズ (プラグイン)に注目するため、HTMLで出力するなどのその他の機能は少し紹介するのみになります。

## Pybtex

[Pybtex](https://pybtex.org)とは、Pythonで書かれたbibliographyプロセッサーで、いつもの`$bibtex hoge`を`$pybtex hoge`と置き換えることができます。

https://pybtex.org

インストールはとても簡単:

```
pip install pybtex
```

PybtexはPythonを使って、次のような出力を可能としています。

- HTML
- Markdown
- LaTeX

つまり: PythonでBibtexの処理を置換しつつ、APIを使うことで様々な入出力に対応している

## Pythonic styles

本記事のメインコンテンツです。
通常、Bibtexでは`.bst`ファイルを書くことで引用文献のフォーマットを変更・カスタマイズします。
ですがbstファイルは、若干修正を行うくらいならまだしも、がっつり修正をすると新しい言語を学ぶ並みのコストがかかります。
**Pythonistaの皆様なら、Pythonで書きたいですよね**。

公式のユーザードキュメントには、Pythonの[スタイルについての情報](https://docs.pybtex.org/api/styles.html)が置いてありますが、「詳しくはunsrtのスタイルとかのコードを読んでみて」と書いてあります (まじで情報がない)。
(なお、現状、Pythonnicスタイルはunsrtしか実装されていないようです。)
ベースとなるスタイル(unsrt)を直接編集してもよいですが、今回はplugin機能を使って、外部ファイルからスタイルを追加する方法を紹介します。

https://docs.pybtex.org/api/plugins.html

### pluginの仕組み

(ここは仕組みは興味がなければ飛ばして大丈夫です。)
pluginは、Pythonの中のentry_points機能を利用しています。

entry_points機能は、主には`pip install`したものをコンソールからexeみたいに呼び出さるようにする用途でよく使われます。
参考: [Pythonでグローバルコマンドを含んだパッケージを作る
](https://qiita.com/fetaro/items/bb0eb8292127b5d1e9a8)

詳細な仕組みは公式情報を眺めた方が良いでしょう。

https://packaging.python.org/ja/latest/specifications/entry-points/

`'pybtex.style.formatting'`など、特定の名前をpluginの名前として約束しておき、`pip`を通じて登録されたpluginを読み込む仕組みになっています。

### pluginの雛形

今回、下記のようなディレクトリで作業を行う想定です。

- root/
    - paper.tex
    - reference.bib
    - tools/
        - pybtex/
            - setup.py
            - mystyle.py

今回は最も基本のスタイルのプラグインを作成してみます。
setup.pyには下記のように記述します。

```setup.py
from setuptools import setup

setup(name='Pybtex-MyStyle',
    author='Take-Me',
    py_modules=['mystyle'],
    entry_points = {
        'pybtex.style.formatting': 'mystyle = mystyle:MyStyle',
    },
    install_requires = ['pybtex']
)
```

まずはunsrtのスタイルを継承しただけのプラグインを作成してみます。

```mystyle.py
from pybtex.style.formatting.unsrt import Style as UnsrtStyle

class MyStyle(UnsrtStyle):
    pass
```

次に、Styleのプラグインには不具合があるので、pybtexコード本体を修正します。
※issue建てた: [the style argument passed via the command line is ignored](https://bitbucket.org/pybtex-devs/pybtex/issues/439/the-style-argument-passed-via-the-command)
site-packages/pybtex/\_\_init\_\_.pyの53行目を下記のように変更します。

```diff_python:pybtex/__init__.py
class Engine(object):
    def make_bibliography(self, aux_filename, style=None, output_encoding=None, bib_format=None, **kwargs):
        """
        Read the given ``.aux`` file and produce a formatted bibliography
        using :py:meth:`~.Engine.format_from_files`.

        :param style: If not ``None``, use this style instead of specified in the ``.aux`` file.
        """

        from pybtex import auxfile
        if bib_format is None:
            from pybtex.database.input.bibtex import Parser as bib_format

        aux_data = auxfile.parse_file(aux_filename, output_encoding)

        if style is None:
            style = aux_data.style
        base_filename = path.splitext(aux_filename)[0]
        bib_filenames = [filename + bib_format.default_suffix for filename in aux_data.data]
        return self.format_from_files(
            bib_filenames,
-           style=aux_data.style,
+           style=style,
            citations=aux_data.citations,
            output_encoding=output_encoding,
            output_filename=base_filename,
            add_output_suffix=True,
            **kwargs
        )
```

なお修正しなくても、tex側でスタイルを`\bibliographystyle{mystyle}`としてもたぶん大丈夫です。

これで、`pip install -e tools/pybtex`とすれば、プラグインが認識されます(開発中は`-e`を使っておくことをお勧めします)。
Latexのコンパイル時に`bibtex paper`としていたのを`pybtex --style-language python -s mystyle paper`と変えてみましょう。

`--style-language python`で処理系をPythonに指定し、`-s mystyle`で先ほど定義したスタイル名を指定します。
Pybtex本体のコードに修正をしない場合は、Tex側で`\bibliographystyle{mystyle}`としてください。多分動きます。

### pluginの実装例

unsrtだと、微妙にフォーマットが合わないことがあると思います。
unsrtのフォーマットは下記のようになっています。

![unsrtのフォーマット](https://camo.qiitausercontent.com/083dad9ceae9576173b2c3f21579325b9894312a/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f33323931322f39613332353439372d623563612d343838362d666561632d3235643334383333623861632e706e67)
図1: unsrtのフォーマット例, [LaTexの参考文献表示スタイルについて](https://qiita.com/izayoi5776/items/6bc577e12fec7730f72b)より

自分が先日Extended Abstractを投稿した学会では、articleの引用形式は下記でした。

```latex
Author, ``Hoge Method of Fuga,'' {\em Nature Neuroscience}, Vol. 123, pp. 12–34, 2022.
```

図1の[1]がunsrtのデフォルトですが、著者の名前の最後は「.」->「,」だし、タイトルは「``''」で囲んでほしいし、volumeは「Vol. 」をつけたいし...とまぁかなり異なります。
ということで、まずはunsrtを継承しているけれど、タイトルは囲むようにするプラグインを実装してみます。

今回は次のpaper.texとreference.bibを用います。

```paper.tex
\documentclass[twocolumn,a4paper]{article}

\begin{document}

\section{Introduction}

Previous method \cite{Exmaple1,Exmaple2,Exmaple3}...

\bibliographystyle{mystyle}
\bibliography{reference}

\end{document}
```

```reference.bib
@article{Exmaple1,
  author  = {H. Fuga},
  journal = {Nature Physics},
  title   = {Hoge Method for Estimating Hidden State},
  volume  = {6},
  year    = {2022},
  pages   = {120--123}
}

@article{Exmaple2,
  author  = {H. F. Piyo and P. Hoge},
  journal = {journal of hoge},
  title   = {A estimation method for non-Gaussian models},
  year    = {1993}
}

@article{Exmaple3,
  author  = {A. B. Ceria and D. Elen and F. Gause},
  journal = {Neuron},
  title   = {Simulation method for Hoge models},
  volume  = {5},
  year    = {2018},
  pages   = {5--20}
}
```

unsrtを継承しただけのプラグインだと、次のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483769/9956bcab-2e9e-2e81-9f95-569f2513095d.png)

それでは、まずは次のようにタイトルをフォーマットしているメソッドをoverrideします。

```mystyle.py
from pybtex.style.formatting.unsrt import Style as UnsrtStyle

from pybtex.database import Entry
from pybtex.richtext import Text

from pybtex.style.template import (
    field, sentence
)

class MyStyle(UnsrtStyle):
    def format_title(self, entry: Entry, which_field = 'title', as_sentence=True):
        def apply(title: Text) -> str:
            raw = str(title)
            return f"``{raw}''"
        
        formatted_title = field(
            which_field, apply_func = apply
        )
        if as_sentence:
            return sentence [ formatted_title ]
        else:
            return formatted_title
```

Pybtexの`UnsrtStyle.format_title`を参考に見てください。(分かりやすさのために、型をつけています。)
`format_title`は、`entry`で表されるそれぞれの引用文献に対して、タイトルのスタイルを指定して返す役割を担っています。`field('title')`で今処理している`entry`のtitle属性を表す`Node`を取得します。
また`sentence`を使うと、文末にピリオドが付くようです。
なおPybtexではこのように`[]`を用いてスタイリングするのも特色の一つです。

:::note
`Node`はテンプレートのような存在です。Pybtexではテンプレート(Nodeの集合みたいなの)をStyleクラスが作成して返却し、実際のデータをengineが描画するシステムになっています。これによってHTML/Markdownの出力などを可能にしてるっぽいです。
:::

自分はpdflatexを使ってコンパイラしているので、次のようにコンパイルします。適宜お好きな方法でビルドしてください。
```shell
pdflatex.exe -output-directory=out ./paper.tex
pybtex --style-language python -s mystyle .\out\paper.aux
pdflatex.exe -output-directory=out ./paper.tex
pdflatex.exe -output-directory=out ./paper.tex
```

すると、次のようにタイトルが囲われます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483769/481564a4-2e4a-7fcc-87f0-14d6ebfb0b93.png)
ただ、「``Tilte of the paper,''」という風に、文頭だけ大文字で、カンマを付与したい、またGaussianなど人名由来のもの / FFJORDなどの略称はそのままというフォーマットだったので、自分は次のように実装しています。

```diff_python:mystyle.py
+ import re
from pybtex.style.formatting.unsrt import Style as UnsrtStyle

from pybtex.database import Entry
from pybtex.richtext import Text

from pybtex.style.template import (
    field, sentence
)

class MyStyle(UnsrtStyle):
    def format_title(self, e: Entry, which_field = 'title', **kwargs):
        def apply(title: Text) -> str:
            raw = str(title)
            # 略字を抜き出す ex: FFJORD, GPTなど.
+           abbreviations: list[str] = re.findall(r'\w*([A-Z]{2,}[A-Z\-]{2,})\w*', raw)
+           raw = raw.capitalize()
            
            # capitalizeで小文字になってしまった部分を置換する
+           for abbreviation in abbreviations:
+               raw = re.sub(abbreviation, abbreviation, raw, flags=re.IGNORECASE)
            
            # 特定の人名などは大文字に直す
+           for name in ["Gaussian"]:
+               raw = raw.replace(name.lower(), name)
            
            return f"``{raw},''"
        
        formatted_title = field(
            which_field, apply_func = apply
        )
        return formatted_title
```

するとこうなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483769/1d442c46-d280-713e-8719-6ddca21801c8.png)

これでタイトルはいじれましたが、volumeなどの存在しない可能性があるフィールドは`format_volume`などのメソッドがありません。そういったフィールドは、`get_article_template`をoverrideして定義します。

unsrtの場合は次のようになっています。

```pybtex/style/formatting/unsrt.py

def dashify(text):
    dash_re = re.compile(r'-+')
    return Text(Symbol('ndash')).join(text.split(dash_re))

pages = field('pages', apply_func=dashify)
date = words [optional_field('month'), field('year')]

class Style(BaseStyle):
    # ... (略)
    def get_article_template(self, e):
        volume_and_pages = first_of [
            optional [
                join [
                    field('volume'),
                    optional['(', field('number'),')'],
                    ':', pages
                ],
            ],
            # pages only
            words ['pages', pages],
        ]
        template = toplevel [
            self.format_names('author'),
            self.format_title(e, 'title'),
            sentence [
                tag('em') [field('journal')],
                optional[ volume_and_pages ],
                date],
            sentence [ optional_field('note') ],
            self.format_web_refs(e),
        ]
        return template
```

`first_of`は空ではない先頭の`Node`を返却する`Node`です。
`optional`は空の`field`が含まれていれば空の`Node`を返し、そうでなければ与えられた`Node`を返します。
`optional_field('field')`は`optional[field('field')]`のエイリアスです。
※空の`Node`は描画される時に無視されるという程度の意味合いです。

これによって、unsrtではvolumeが存在するarticleで、変数`volume_and_pages`は「volume: pages 」のテンプレートを表す`Node`になります。(numberが存在すれば「volume(number): pages」になる。)
`join`はその名前の通り、与えられた`Node`を連結します。デフォルトではスペースなしでくっつきます。

:::note warn
ここでいう空のfieldとは、bibファイルで定義されていないという意味です。
`volume = {},`のように、キーが書かれていて値がない場合は、**フィールドは空ではない**と判定されるようです。
また空の`Node`は描画されないので、
:::

当時の形式の場合、URLは不要で、「Vol. volume, No. number, pp. pages, year.」という形にしたかったので、次のような形になりました。

```diff_python:mystyle.py
from pybtex.style.template import (
-   field, sentence
+   field, sentence, tag, optional
)
class MyStyle(UnsrtStyle):
    def format_title(self, e: Entry, which_field = 'title', as_sentence=True):
        ...  # 省略

+   def get_article_template(self, entry: Entry):    # このメソッドを追加
        template = toplevel[
            self.format_names('author'),
            self.format_title(entry, 'title'),
            sentence[    # ', 'で繋いで最後にピリオドを追加する
                tag('em')[field('journal')],
                optional['Vol. ', field('volume')],
                optional['No. ', field('number')],
                optional['pp. ', field('pages')],
                field('year')
            ],
        ]
        return template
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483769/ee363895-adf8-ccc1-82d0-ac2bb7339a68.png)

おっと、著者の名前の最後はピリオドではなくカンマで区切って欲しいと先生に言われました。
`format_names`もoverrideしましょう。

```diff_python:mystyle.py
from pybtex.style.template import (
-   field, sentence, tag, optional
+   field, sentence, tag, optional, names, join
)
class MyStyle(UnsrtStyle):
+   def format_names(self, role, as_sentence=True):    # このメソッドを追加
        formatted_names = names(role, sep=', ', sep2 = ' and ', last_sep=', and ')
        return join[ formatted_names, ', ' ]
    # ... (省略)
```

`names`は名前をいい感じに取得する`Node`だと思ってください。
結果こうなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483769/2aac62ca-ac52-052c-5bac-b587e502528d.png)

え？journalは「journal of hoge」じゃなくて「Journal of Hoge」みたいにして？
これはここまでの知識でできますよね。

```diff_python:mystyle.py
# ... (省略)
class MyStyle(UnsrtStyle):
    # ... (省略)
+   def format_journal(self):    # このメソッドを追加
        def apply(title: Text) -> str:
            raw = str(title)
            raw = raw.title()
            # ofなどは元に戻す
            should_be_lowered = ['of', 'and']
            for word in should_be_lowered:
                raw = raw.replace(word.title(), word.lower())
            return raw
        
        formatted_journal = tag('em')[field('journal', apply_func = apply)]
        return formatted_journal

    def get_article_template(self, entry: Entry):
        template = toplevel[
            self.format_names('author'),
            self.format_title(entry, 'title'),
            sentence[
-               tag('em')[field('journal')],
+               self.format_journal(),
                optional['Vol. ', field('volume')],
                optional['No. ', field('number')],
                optional['pp. ', field('pages')],
                field('year')
            ],
        ]
        return template
```

ヨシ！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483769/6b7ee2aa-6f9e-b193-baa7-3271700a3c5e.png)

## 名前のスタイル

ここまでの例では、名前のスタイルが予め揃っているケース(H. Fugaなど)でしたが、場合によっては名前のスタイルがそろっていない場合がありますよね。
bibファイルを編集してもよいですが、執筆の度にスタイルを修正するのは面倒なので、名前のスタイルもプラグインを作成して編集してみます。

### 問題設定

先ほどのpaper.texとreference.bibに少し加筆したものを扱います。

```diff:paper.tex
\documentclass[twocolumn,a4paper]{article}

\begin{document}

\section{Introduction}

- Previous method \cite{Exmaple1,Exmaple2,Exmaple3}...
+ Previous method \cite{Exmaple1,Exmaple2,Exmaple3,Example4}...

\bibliographystyle{mystyle}
\bibliography{reference}

\end{document}
```

```reference.bib
// 下記を追加
@article{Exmaple4,
  author  = {Abc B. Ceria and Daniel Elen},
  journal = {Neuron},
  title   = {Simulation method for Hoge models},
  volume  = {5},
  year    = {2018},
  pages   = {5--20}
}

@article{Exmaple5,
  author  = {Thomas Alva Edison},
  journal = {Test},
  number  = {33},
  title   = {Hoge Fuga Hogefuga},
  volume  = {4},
  year    = {2019}
}
```

先ほど作成したプラグインだと、次のようにコンパイルされます。

```
[4] Abc B. Ceria and Daniel Elen, “Simulation method for hoge models,” Neuron, Vol. 5, pp. 5–20, 2018.
[5] Thomas Alva Edison, “Hoge fuga hogefuga,” Test, Vol. 4, No. 33, 2019.
```

この結果を次のように変更したいです。これが今回の要件です。

```
[4] A. Ceria and D. Elen, “Simulation method for hoge models,” Neuron, Vol. 5, pp. 5–20, 2018.
[5] T. Edison, “Hoge fuga hogefuga,” Test, Vol. 4, No. 33, 2019.
```

:::note
実はpybtexのコマンドライン引数に`--abbreviate-names`というフラグ変数が存在します。これを指定すると次のようにファーストネームとミドルネームが省略されます。
```
[4] A. B. Ceria and D. Elen, “Sim-
ulation method for hoge models,” Neuron, Vol.
5, pp. 5–20, 2018.
```
ただし、ミドルネームを省略したいケースや、長い人名で一部分を抜き出したいケースではプラグインを作成する必要があります。
なお、`Last First Middle`の順番にしたい時は既定のスタイル「lastfirst」で実現可能です。
```shell
pybtex --style-language python --name-style=lastfirst .\out\paper.aux
# `--abbreviate-names`と併用可能です。
pybtex --style-language python --name-style=lastfirst --abbreviate-names .\out\paper.aux
```
:::

### プラグインの雛形作成

名前のスタイルのプラグインは、`setup.py`にプラグインを定義するクラスを指定をして、対応するクラスを定義します。

```diff_python:setup.py
from setuptools import setup

setup(name='Pybtex-MyStyle',
    author='Take-Me',
    py_modules=['mystyle'],
    entry_points = {
        'pybtex.style.formatting': 'mystyle = mystyle:MyStyle',
+       'pybtex.style.names': 'mystyle = mystyle:MyNameStyle',
    },
    install_requires = ['pybtex']
)
```

mystyle.pyにも下記を追加します。
※これは雛形です。`PlainNameStyle`のメソッドをコピペしています。

```mystyle.py
from pybtex.database import Person
from pybtex.style.names.plain import NameStyle as PlainNameStyle
from pybtex.style.names import name_part

class MyNameStyle(PlainNameStyle):
    def format(self, person: Person, abbr=False):
        print(person)    # 呼び出されているのかを確認する為
        return join[
            name_part(tie=True, abbr=abbr)[person.rich_first_names + person.rich_middle_names],
            name_part(tie=True, abbr=abbr)[person.rich_prelast_names],
            name_part[person.rich_last_names],
            name_part(before=', ')[person.rich_lineage_names]
        ]
```

`pip install -e tools/pybtex`でインストールしなおします。(setup.pyを更新したので。)
`pybtex --style-language python --style=mystyle --name-style=mystyle --abbreviate-names .\out\paper.aux`で実行します。当然スタイルは変わっていないと思いますが、正しくプラグインが認識されていれば、次のように`print(person)`の結果が出力されています。
```shell
# 恐らく Last, first (middle) で出力されています。
Fuga, H.
Piyo, H. F.
Hoge, P.
Ceria, A. B.
Elen, D.
Gause, F.
Ceria, Abc B.
Elen, Daniel
Edison, Thomas Alva
```

### プラグインを実装

今回は次のように、abbreviateを常にTrueにして、middleネームを省略する方向で実装します。

```diff_python:mystyle.py
class MyNameStyle(PlainNameStyle):
    def format(self, person: Person, abbr=False):
        return join[
-           name_part(tie=True, abbr=abbr)[person.rich_first_names + person.rich_middle_names],
+           name_part(tie=True, abbr=True)[person.rich_first_names],
-           name_part(tie=True, abbr=abbr)[person.rich_prelast_names],
+           name_part[person.rich_last_names],
-           name_part(before=', ')[person.rich_lineage_names]
        ]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483769/cfbb4113-7b22-9590-1d45-f87a2f715912.png)

ヨシ！

## Tips

### 日本語のタイトル名の時は`em`してほしくない時

`tag("em")`をつけると、強調になり、アルファベットの場合には*italic*になります。
一方で日本語の場合には**太字**になります。
漢字を含む≒日本語の時には、太字にしない場合は、次のような処理をいれることを提案します。

```python
def is_kanji(s: str):
    # マルチバイト文字 ～ 漢字を判定
    # TODO: 簡易にも程があるので状況に応じて変えてください
    return len(s) != len(s.encode('utf-8'))

class MyStyle(UnsrtStyle):
    def format_title(self, e: Entry, which_field = 'title', **kwargs):
        def apply(title: Text) -> Node | str:
            raw = str(title)
            
            if not is_kanji(raw):
                return tag("em")[raw].format_data(title)
            return raw

        formatted_title = sentence[field("title", apply_func=apply)]
        return formatted_title
```

そもそも、`format_title`を呼び出した時点では、処理する対象は恐らく決まっておらず、後から実際のエントリーが渡されます。
したがって`format_title`の時点では、扱う対象が日本語か英語かを判定できていない...はず。
一方で`apply_func`に渡された関数が呼ばれるタイミングは、実際の参考文献が渡されたタイミングです。
そこで`apply`で処理を挟んで、そのタイミングで`tag("em")`をつける付けないを判定します。

扱う参考文献が全て日本語/英語ならこんなことしなくてもよいのですが、卒論修論ではこんなことになったので…備忘録として残しておきます。

## まとめ

本記事では、[Pybtex](https://pybtex.org)というPythonでbibtexのスタイルをカスタマイズ可能なパッケージを紹介しました。
bstファイルが与えられる学会では問題ありませんが、与えらえない学会ではフォーマットを揃えたりする面倒な手作業を行う必要がありますよね。bstファイルを自作するよりも、Pythonistaならこれを使った方がきっと早いでしょう。
本記事では、実際にありそうなフォーマットを想定してプラグインを作成してみました。

Pybtexはただでさえ情報が少ないですが、プラグインに関する情報は皆無であり、論文を添削指導してもらっている間の時間全てを溶かしました。
~~少しでも周知され、開発が活発化することを願っています。~~


## 参考資料

- Pybtexの公式
    - 現状ほぼ唯一の情報源

https://pybtex.org

- 公式のpluginのサンプル
    - デフォルトではサポートされていない形式のファイルから読み込むparserとかもプラグインで定義可能
    - なぜかスタイルファイルのプラグインの公式サンプルはない。けど探すと有志が作ったプラグインがgithubでは見つかる

https://bitbucket.org/pybtex-devs/pybtex/src/HEAD/examples/sample_plugins/

- BiBTex自体の簡単な説明

https://qiita.com/SUZUKI_Masaya/items/14f9727845e020f8e7e9

- bstファイルの文法について

https://qiita.com/HexagramNM/items/7c59f307e55010caf693

- bstファイルで著者名のスタイルを変更する方法

https://tfidf.net/memos/bibtex-bst-first-name-initial.htm