QuartoやR Markdownを使用して論文やレポートを作成している際、kableExtra などのパッケージを用いてテーブルを作成することがあります。その際、セル内に引用(例:@citation)を含めても、それが正しくハイパーリンクや脚注としてレンダリングされず、単なる文字列として出力されてしまう問題に直面することがあります。
この問題は、Pandocの仕様、および使用しているパッケージがテーブルのセル内容を「Raw text(生のテキスト)」として出力してしまうことに起因しています。
問題の背景
通常、PandocはMarkdownとして文書を解析し、@citation を適切な引用要素に変換します。しかし、kableExtra などによって生成されたテーブルのコンテンツが、Pandocにおいて RawBlock や RawInline として渡されてしまうと、Pandocの標準的な引用処理(Citation Processor)をバイパスしてしまいます。
実際に、QuartoのGitHub DiscussionsやPositのフォーラムでも、このような「テーブル内での引用の扱い」に関する議論がいくつか見られます。
解決策:Luaフィルタ fix_kable_citation.lua
この問題を解決するために、Raw textの中に含まれる引用シンボル(@)を検出し、その部分だけを再度Markdownとして再解析してPandocの要素に変換するLuaフィルタを作成しました。
仕組み
このフィルタは以下のステップで動作します。
- ターゲット形式の判定: HTML (
html,html5等) および LaTeX (latex,tex) の Raw要素を対象とします。 - 引用シンボルの検出: テキスト内に
@が含まれているか、あるいは[@citation]のようなブラケット形式が含まれているかをチェックします。 - 再解析:
@を含む部分を抽出し、pandoc.read(text, "markdown")を用いて、その部分だけをMarkdownとして読み込みます。 - 要素の置換: 解析された引用要素を、元のRaw textの代わりに挿入します。
これにより、テーブル内であっても通常の本文と同様に、引用が正しくレンダリングされるようになります。
実装コード (fix_kable_citation.lua)
local function is_target_format(fmt)
return fmt == "latex" or fmt == "tex"
or fmt == "html" or fmt == "html4" or fmt == "html5"
end
local function split_citations(text, fmt)
local inlines = pandoc.List({})
local buf = {}
local i = 1
local n = #text
local function flush_buf()
if #buf > 0 then
inlines:insert(pandoc.RawInline(fmt, table.concat(buf)))
buf = {}
end
end
while i <= n do
local c = text:sub(i, i)
-- [@citation] の処理
if c == "[" then
local bracket = text:match("^%b[]", i)
if bracket and bracket:match("@[%w]") then
local ok, parsed = pcall(pandoc.read, bracket, "markdown")
if ok and #parsed.blocks > 0 then
flush_buf()
for _, blk in ipairs(parsed.blocks) do
if blk.content then
for _, il in ipairs(blk.content) do
inlines:insert(il)
end
end
end
i = i + #bracket
goto continue
end
end
end
-- @citation 形式の処理
if c == "@" then
local prev = text:sub(i - 1, i - 1)
if i == 1 or not prev:match("[%w\\]") then
local bare = text:match("^@[%w][%w%-_:.]*", i)
if bare then
local ok, parsed = pcall(pandoc.read, bare, "markdown")
if ok and #parsed.blocks > 0 then
flush_buf()
for _, blk in ipairs(parsed.blocks) do
if blk.content then
for _, il in ipairs(blk.content) do
inlines:insert(il)
end
end
end
i = i + #bare
goto continue
end
end
end
end
table.insert(buf, c)
i = i + 1
::continue::
end
flush_buf()
return inlines
end
function RawBlock(el)
if not is_target_format(el.format) then return nil end
if not el.text:find("@") then return nil end
local inlines = split_citations(el.text, el.format)
return pandoc.Plain(inlines)
end
function RawInline(el)
if not is_target_format(el.format) then return nil end
if not el.text:find("@") then return nil end
local inlines = split_citations(el.text, el.format)
return inlines
end
使い方
作成した .lua ファイルを、プロジェクトのディレクトリに配置します。
その後、Quarto/R Markdown の YAML ヘッダーに以下のように追加します。
QuartoのYAMLヘッダー
---
title: "My Research Document"
format: html
filters:
- fix_kable_citation.lua
---
RmarkdownのYAMLヘッダー
---
title: "My Research Document"
output:
html_document:
pandoc_args:
- "--lua-filter=fix_kable_citation.lua"
---
これで、kableExtra 等から出力された Raw Text 内の引用が、適切にレンダリングされるようになります。
まとめ
テーブル内での引用問題は、出力形式が Raw Text になることで Pandoc の解析プロセスから外れてしまうことが原因でした。
このLuaフィルタを使用することで、複雑な設定変更をすることなく、既存のワークフローの中でスマートに問題を解決できます。

Amazonアフィリエイトでブログ運営しています。
応援いただけると嬉しいです。

ネスカフェ 香味焙煎 ひとときの贅沢 スティック ブラック 20P,箱,レギュラー ソリュブル コーヒー,個包装

AHMAD TEA(アーマッドティー) クラシックセレクション ティーバッグ 20袋

