Skip to content
Go back

HugoでのCitationの扱いを再び考える

  • 現在、citationを扱う実装はコンテンツ全体に対して直接、置換処理を適用するので、不具合が起こる可能性があった
    • idをcite-@citekeybib-@citekeyにしていたので、複数回@citekeyを置き換えようとすると、置き換え済みのidのほうが置き換わってしまっていた
  • idから@を取り除けば解消するはずだけど、せっかくなので、やり方を他と合わせてみる
    • Wikilinkのときのように、まず先に、置換対象の有無で文字列を別ける処理を全文に対して昇順で行う
    • 置換処理ごとに置換え対象を全文から探さなくて良くなるので、パフォーマンス的に有利かも?

元はこんな感じでした。

{{- $content := .Content -}}

{{- /* @citekeyか[@citekey ...]を見つけてHTMLに置換する */ -}}
{{- range (findRESubmatch `(\[?\[?)(@[\w-\.]+(?:;\s*@[\w-\.]+)*)(\]?\]?)` $content) -}}
    {{- /* [[@citeley]]などの誤検出を弾く */ -}}
    ...

    {{- /* HTMLを作って$resultに入れる */
    {{- $matched := index . 0 -}}
    {{- $citekeys := index . 2 -}}
    {{- $result := "" -}}
    {{- range (findRESubmatch `(;?\s*)(@[\w-\.]+)` $citekeys) -}}
        ...
    {{- end -}}

    {{- /* citationをHTMLで置き換える */ -}}
    {{- $content = replace $content $matched (print "[" $result "]") 1 -}}
{{- end -}}
{{- $content | safeHTML -}}

使える文字種#

  • これを機に、citekeyがドットを含まないようにする?
    • 日本語では問題ないけど、文末にcitationを置けなくなってしまうのでは?
  • BibLaTeXのentrykeyで使える文字種は意外と幅広い
    • 英数字と./-_:;!?はほぼすべての環境で使える
    • Unicode環境なら非ASCII文字も使える
    • {}, \#%~は使用不可
    • biberでは()"'=も追加で使用不可
    • 可搬性を考えると、英数字と.:-程度に収めたほうが良いらしい
  • Pandocのcitation keyでは文脈によっては囲いが必要になる
    • 英数字と_は制限なく使える
    • 文中の句読点internal punctuation:.#$%&-+?<>~/)も使えるが、細かい条件がある
      • 文末の句読点はキーに含まれない
      • 連続する記号はキーを区切る
    • 区切り文字をキーに含めるには{}で囲む
    • おまけに、[-@citekey]とすると著者名が省略される
  • ObsidianでPandoc Reference Listプラグインを使っているので、Pandocの仕様に合わせないといけない
    • ただし、このプラグインは@citekeyの形でしかサジェストしてくれないので、@{citekey}形式は使いづらくなる
  • 結果、思っていたよりそのままで良いかも
    • 現状のキー生成でも問題なさそう
    • Hugo側では、文末の記号を特別扱いするように変更すればよさそう
    • 一応、@{}記法に対応しておいても良いかも?

結果#

  • 以下のようなテンプレートを作った
    • 簡略化のため、文中に連続する記号が現れたときに区切り扱いにする処理を入れていない
    • 細かいところで差異があるけど、問題が起こってから対処します
{{- /* Pandoc式のcitationをHTMLに置き換える */ -}}

{{- /* citation記法を探す */ -}}
{{- range (findRESubmatch `(?:((?:.|\n)*?)(?:(\[\[@[\w\.:-]+\]\])|(\[@[\w\.:-]+(?:; *@[\w\.:-]+)*\])|(@[\w.:-]+)))|((?:.|\n)*)` .Content) -}}

    {{- with index . 5 -}}
        {{- /* 記法が見つからない場合、未加工で出力する */ -}}
        {{- . | safeHTML -}}
    {{- end -}}

    {{- /* 記法が見つかった場合、関係のない部分は未加工で出力する */ -}}
    {{- index . 1 | safeHTML -}}

    {{- with index . 2 -}}
        {{- /* [[@citekey]]形式の場合、wikilink形式として扱うので、ここでは未加工で出力する */ -}}
        {{- . | safeHTML -}}
    {{- else with index . 3 -}}
        {{- /* [@citekey ...]形式の場合 */ -}}
        <span class="citation">[
        {{- range (findRESubmatch `(;? *)@([\w\.:-]+)` .) -}}
            {{- $spacing := index . 1 -}}
            {{- $citekey := index . 2 -}}

            {{- /* citekeyと同名のノートを探す */ -}}
            {{- $url := relref page (print "@" $citekey ".md") -}}

            {{- /* ノートが見つからなければ、未加工で出力する */ -}}
            {{- if not $url -}}
                {{- index . 0 -}}
                {{- continue -}}
            {{- end -}}

            {{- /* citekeyを一覧に追加して、番号を得る */ -}}
            {{- $count_key := print "ref." $citekey ".Count" -}}
            {{- $count := add (or ($.Store.Get $count_key) 0) 1 -}}
            {{- $.Store.Set $count_key $count -}}
            {{- $.Store.Add "ref.Citekeys" (slice $citekey) -}}

            {{- /* ノートから文献情報を取得する */ -}}
            {{- $page :=  site.GetPage $url -}}
            {{- $info := index $page.Params "zt-info" -}}

            {{- if $info -}}
                {{- $spacing -}}
                {{- partial "make-citation.html" (dict "author_in_text" false "index" $count "info" $info "url" $url) -}}
            {{- else -}}
                {{- /* 文献情報が見つからなければ、未加工で出力する */ -}}
                {{- index . 0 -}}
            {{- end -}}
        {{- end -}}
        ]</span>
    {{- else with index . 4 -}}
        {{- /* @citekey形式の場合 */ -}}
        <span class="citation">
        {{- range (findRESubmatch `(?:@([\w\.:-]+?)([\.:-]*)$)|(?:@([\w\.:-]+))` .) -}}
            {{- $citekey := or (index . 1) (index . 3) -}}
            {{- $punct := index . 2 -}} {{- /* 末尾の句読点はキーに含まれない */ -}}

            {{- /* citekeyと同名のノートを探す */ -}}
            {{- $url := relref page (print "@" $citekey ".md") -}}

            {{- /* ノートが見つからなければ、未加工で出力する */ -}}
            {{- if not $url -}}
                {{- index . 0 -}}
                {{- continue -}}
            {{- end -}}

            {{- /* citekeyを一覧に追加して、番号を得る */ -}}
            {{- $count_key := print "ref." $citekey ".Count" -}}
            {{- $count := add (or ($.Store.Get $count_key) 0) 1 -}}
            {{- $.Store.Set $count_key $count -}}
            {{- $.Store.Add "ref.Citekeys" (slice $citekey) -}}

            {{- /* ノートから文献情報を取得する */ -}}
            {{- $page :=  site.GetPage $url -}}
            {{- $info := index $page.Params "zt-info" -}}

            {{- if $info -}}
                {{- partial "make-citation.html" (dict "author_in_text" true "index" $count "info" $info "url" $url) -}}
                {{- $punct -}}
            {{- else -}}
                {{- /* 文献情報が見つからなければ、未加工で出力する */ -}}
                {{- index . 0 -}}
            {{- end -}}
        {{- end -}}
        </span>
    {{- end -}}
{{- end -}}

Last [2025Last, F. 2025. Example.]

[Last 2025Last, F. 2025. Example.]

[[ Last 2025Last, F. 2025. Example.]]

参考資料#