漢文訓読文を表示するためのモジュールです。

使用法

編集

例:

{{#invoke:Kanbun|kanbun|
桃 之 夭 夭^(タル) \O 灼 灼^(タリ) 其^(ノ) 華 \N
之^(ノ) 子 于^(キ) 帰^(グ) \O 宜_(二)^(シカラン) 其^(ノ) 室 家_(一)^(ニ) \N \N

桃 之^(ノ) 夭 夭^(タル) \O 有^(リ)_(レ) 蕡^(タル) 其^(ノ) 実 \N
之^(ノ) 子 于^(キ) 帰^(グ) \O 宜^(シカラン)_(二) 其^(ノ) 家 室^(ニ)_(一) \N \N

桃 之 夭 夭^(タル) \O 其^(ノ) 葉 蓁 蓁^(タリ) \N
之^(ノ) 子 于^(キ) 帰^(グ) \O 宜_(二)^(シカラン) 其^(ノ) 家 人_(一)^(ニ)
}}

出力:

タル タリ
 シカラン

タル タル
 シカラン

タル タリ
 シカラン

漢字は半角スペースで区切ります。 ^()で囲んだ部分は送り仮名や読み仮名を表し、_()で囲んだ部分は返り点を表します。 入力中の改行は漢字の区切り部分であれば出力に影響しません。出力で改行を挿入する場合は、\Nを使用します。

特別な記号

  • \N:改行を挿入する。
  • \O:空白を挿入する。
  • \T:読点を挿入する。テン(Ten)に由来する。
  • \M:句点を挿入する。マル(Maru)に由来する。
  • \H:ハイフンを含む場合に使用する。

local p = {}

local kunten = {
    ["レ"] = "㆑", -- 返り点には U+3191からU+319Fを使う。
    ["一"] = "㆒",
    ["二"] = "㆓",
    ["三"] = "㆔",
    ["四"] = "㆕",
    ["上"] = "㆖",
    ["中"] = "㆗",
    ["下"] = "㆘",
    ["甲"] = "㆙",
    ["乙"] = "㆚",
    ["丙"] = "㆛",
    ["丁"] = "㆜",
    ["天"] = "㆝",
    ["地"] = "㆞",
    ["人"] = "㆟",
    ["一レ"] = "㆒㆑",
    ["上レ"] = "㆖㆑",
    ["甲レ"] = "㆙㆑",
    ["天レ"] = "㆝㆑"
}

function p.kanbun(frame)
    local input_text = frame.args[1]
    local html_output = '<div style="writing-mode: vertical-rl; font-size: 150%; white-space: nowrap;">'
    local shift = "0"
    for char in string.gmatch(input_text, "%S+") do
        local kanzi = char:match("^(.-)[_^]") or char
        local okurigana = char:match("%^%((.-)%)")
        local kaeriten = char:match("_%((.-)%)")
        local saidoku = char:match("s%((.-)%)")
        local symbol = char:match("\\(.)")

        if symbol == "O" then
            kanzi = " "
        end

        if symbol == "N" then
            html_output = html_output .. "<br>"
            shift = 0
        else

            -- 漢字
            html_output = html_output .. string.format(
                '<span style="display: inline-block; position: relative; margin-left: 0.5em; margin-right: 0.5em; margin-top: 0.4em; margin-bottom: 0.5em; bottom: -%sem">%s',
                shift, kanzi)

            if symbol == "M" then
                html_output = html_output .. [[<span style="position: absolute; bottom: -1em;">。</span>]]
            end

            if symbol == "T" then
                html_output = html_output .. [[<span style="position: absolute; bottom: -1em;">、</span>]]
            end

            -- 返り点
            if kaeriten then
                kaeriten = kunten[kaeriten] or kaeriten

                if symbol == "H" then
                    html_output = html_output ..
                                      string.format(
                            '<span style="position: absolute; font-size: 50%%; top: 1.8em; left: -0.25em;">%s</span>',
                            kaeriten)

                else
                    if kaeriten == "㆒㆑" then
                        html_output = html_output ..
                                          [[<span style="position: absolute; font-size: 50%; bottom: -1em; left: 0.25em;">㆒</span><span style="position: absolute; font-size: 50%; bottom: -1.35em; left: 0.25em;">㆑</span>]]

                    elseif kaeriten == "㆖㆑" then
                        html_output = html_output ..
                                          [[<span style="position: absolute; font-size: 50%; bottom: -1em; left: 0.25em; transform: scaleY(0.6);">㆖</span><span style="position: absolute; font-size: 50%; bottom: -1.45em; left: 0.25em; transform: scaleY(0.6);">㆑</span>]]

                    elseif kaeriten == "㆙㆑" then
                        html_output = html_output ..
                                          [[<span style="position: absolute; font-size: 50%; bottom: -1em; left: 0.25em; transform: scaleY(0.6);">㆙</span><span style="position: absolute; font-size: 50%; bottom: -1.4em; left: 0.25em; transform: scaleY(0.6);">㆑</span>]]

                    elseif kaeriten == "㆝㆑" then
                        html_output = html_output ..
                                          [[<span style="position: absolute; font-size: 50%; bottom: -1em; left: 0.25em; transform: scaleY(0.6);">㆝</span><span style="position: absolute; font-size: 50%; bottom: -1.4em; left: 0.25em; transform: scaleY(0.6);">㆑</span>]]

                    else
                        html_output = html_output ..
                                          string.format(
                                '<span style="position: absolute; font-size: 50%%; bottom: -1em; left: 0.25em;">%s</span>',
                                kaeriten)
                    end

                end

            end

            -- 送り仮名
            if okurigana then

                -- ひらがなとカタカナの個数を計算
                local hiraganumber = 0
                local katakanumber = 0

                local i = 1
                while i <= #okurigana do
                    local byte = string.byte(okurigana, i)
                    local second = string.byte(okurigana, i + 1)
                    local third = string.byte(okurigana, i + 2)

                    local codepoint = ((byte % 16) * 2 ^ 12) + ((second % 64) * 2 ^ 6) + (third % 64)

                    if codepoint >= 0x3041 and codepoint <= 0x309F then
                        hiraganumber = hiraganumber + 1
                    elseif codepoint >= 0x30A0 and codepoint <= 0x30FF then
                        katakanumber = katakanumber + 1
                    end

                    i = i + 3
                end

                -- 位置の調整
                local bottom = nil
                local top = nil

                if hiraganumber == 0 and katakanumber == 1 then
                    bottom = "-0.5"

                elseif hiraganumber == 0 and katakanumber == 2 then
                    bottom = "-1"

                elseif hiraganumber == 0 and katakanumber == 3 then
                    bottom = "-2"

                elseif hiraganumber == 0 and katakanumber == 4 then
                    bottom = "-2.5"

                elseif hiraganumber == 1 and katakanumber == 0 then
                    bottom = "0.5"

                elseif hiraganumber == 2 and katakanumber == 0 then
                    bottom = "0"

                elseif hiraganumber == 3 and katakanumber == 0 then
                    bottom = "-0.5"

                elseif hiraganumber == 4 and katakanumber == 0 then
                    bottom = "-1"

                elseif hiraganumber == 1 and katakanumber == 1 then
                    bottom = "-0.5"

                elseif hiraganumber + katakanumber >= 5 then
                    top = "-1"
                    shift = tonumber(shift) + tostring(0.5 * (hiraganumber + katakanumber - 4))

                else
                    bottom = "-1"
                end

                if bottom then
                    html_output = html_output .. string.format(
                        '<span style="position: absolute; font-size: 50%%; bottom: %sem; right: -0.5em; white-space: nowrap;">%s</span>',
                        bottom, okurigana)
                else
                    html_output = html_output .. string.format(
                        '<span style="position: absolute; font-size: 50%%; top: %sem; right: -0.5em; white-space: nowrap;">%s</span>',
                        top, okurigana)
                end

            end

            if saidoku then
                html_output = html_output .. string.format(
                    '<span style="position: absolute; font-size: 50%%; bottom: 0em; left: -0.5em; white-space: nowrap;">%s</span>',
                    saidoku)
            end

            html_output = html_output .. "</span>"
        end
    end

    html_output = html_output .. "</div>"

    return html_output
end

return p