跳至內容

模組:LumineRelations

出自微國家百科

可在模組:LumineRelations/doc建立此模組的說明文件

--[[
================================================================================
Module:LumineRelations
盧米涅企業共和國 外交關係統計模組
================================================================================

【功能說明】
本模組從「盧米涅企業共和國」頁面的外交表格中自動讀取資料,
計算各項外交統計數值,供 infobox 或正文引用,避免手動維護數字。

【關鍵設計說明】
  每張 AutonumTable 的 id(|id=XXX|class=...}})位於表格「結尾」。
  因此某張表格的列內容,位於「前一個表格的 id」到「本表格的 id」之間。
  本模組使用 countBetween(prevId, thisId) 的方式準確計算每張表格的列數。

  頁面中表格的實際順序(必須與頁面一致,否則計算錯誤):
    (開頭) → luminebang → luminejing → lumineunilateral → lumineorg
           → luminedc → luminetreaty → luminehistbang → luminehistorg → (結尾)

【可用函式一覽】
  --- 正式邦交國 ---
  {{#invoke:LumineRelations|bangTotal}}        → 邦交國總數
  {{#invoke:LumineRelations|bangAmbassador}}   → 大使級邦交國數
  {{#invoke:LumineRelations|bangMinister}}     → 公使級邦交國數
  {{#invoke:LumineRelations|bangCharge}}       → 代辦級邦交國數
  {{#invoke:LumineRelations|bangNA}}           → 不適用(特殊外交安排)邦交國數
  {{#invoke:LumineRelations|bangFormal}}       → 大使+公使+代辦加總(驗算用)

  --- 經濟文化代表處 ---
  {{#invoke:LumineRelations|jingTotal}}        → 設立經濟文化代表處總數

  --- 單方承認主權 ---
  {{#invoke:LumineRelations|uniTotal}}         → 單方承認主權國家總數

  --- 加入國際組織 ---
  {{#invoke:LumineRelations|orgTotal}}         → 加入國際組織總數

  --- 深度合作Discord組織 ---
  {{#invoke:LumineRelations|dcTotal}}          → 深度合作Discord組織總數

  --- 同盟及合作協議 ---
  {{#invoke:LumineRelations|treatyTotal}}      → 締結條約總數
  {{#invoke:LumineRelations|treatyMilitary}}   → 含軍事性質條約數
  {{#invoke:LumineRelations|treatyOther}}      → 非軍事性質條約數

  --- 歷史邦交國(已斷交)---
  {{#invoke:LumineRelations|histTotal}}        → 歷史邦交國總數
  {{#invoke:LumineRelations|histExtinct}}      → 因亡國斷交的數量
  {{#invoke:LumineRelations|histMerged}}       → 因併入他國斷交的數量
  {{#invoke:LumineRelations|histOther}}        → 其他原因斷交的數量

  --- 歷史參與國際組織(已退出)---
  {{#invoke:LumineRelations|histOrgTotal}}     → 曾加入但已退出的組織總數
  {{#invoke:LumineRelations|histOrgDissolved}} → 因組織解散退出的數量
  {{#invoke:LumineRelations|histOrgLeft}}      → 主動退出的數量

  --- 綜合統計 ---
  {{#invoke:LumineRelations|allTotal}}         → 邦交國+代表處+組織總計
  {{#invoke:LumineRelations|everTotal}}        → 曾建交總數(現有+歷史邦交國)

【正文使用範例】
  截至目前,盧米涅共與{{#invoke:LumineRelations|bangTotal}}個國家建立正式外交關係,
  其中大使級{{#invoke:LumineRelations|bangAmbassador}}個、
  公使級{{#invoke:LumineRelations|bangMinister}}個、
  代辦級{{#invoke:LumineRelations|bangCharge}}個。
  另設有{{#invoke:LumineRelations|jingTotal}}處經濟文化代表處,
  並加入{{#invoke:LumineRelations|orgTotal}}個國際組織。

【維護說明】
  - 新增或移除表格列後,只需儲存「盧米涅企業共和國」頁面,數字自動更新。
  - 若頁面名稱更改,修改 TARGET_PAGE 常數。
  - 若表格 id 或順序更改,必須同步修改下方常數。

================================================================================
]]

local p = {}

-- ============================================================
-- 常數設定
-- ============================================================

local TARGET_PAGE = "盧米涅外交"

-- 頁面中各表格的 id(順序必須與頁面實際順序一致)
local ID_BANG    = "luminebang"       -- 正式邦交國
local ID_JING    = "luminejing"       -- 經濟文化代表處
local ID_UNI     = "lumineunilateral" -- 單方承認主權
local ID_ORG     = "lumineorg"        -- 加入國際組織
local ID_DC      = "luminedc"         -- 深度合作Discord組織
local ID_TREATY  = "luminetreaty"     -- 同盟及合作協議
local ID_HIST    = "luminehistbang"   -- 歷史邦交國(已斷交)
local ID_HISTORG = "luminehistorg"    -- 歷史參與國際組織(已退出)

-- ============================================================
-- 內部工具函式
-- ============================================================

local function getContent()
    return mw.title.new(TARGET_PAGE):getContent() or ""
end

-- 計算字串中 AutonumTable/index 的出現次數
local function countIndex(s)
    local n = 0
    for _ in s:gmatch("AutonumTable/index") do n = n + 1 end
    return n
end

-- 核心函式:計算從 prevId 到 thisId 之間的 index 數
-- 因為 id 在表格結尾,所以 prevId~thisId 之間的內容正好是 thisId 對應表格的所有列
-- prevId=nil 表示從頁面開頭,thisId=nil 表示到頁面結尾
local function countBetween(content, prevId, thisId)
    local startPos = 1
    if prevId then
        startPos = content:find("id=" .. prevId)
        if not startPos then return 0 end
    end
    local endPos = #content
    if thisId then
        endPos = content:find("id=" .. thisId, startPos)
        if not endPos then return 0 end
    end
    return countIndex(content:sub(startPos, endPos))
end

-- 擷取 prevId 到 thisId 之間的字串(用於進一步比對欄位值)
local function getSection(content, prevId, thisId)
    local startPos = 1
    if prevId then
        startPos = content:find("id=" .. prevId)
        if not startPos then return "" end
    end
    local endPos = #content
    if thisId then
        endPos = content:find("id=" .. thisId, startPos)
        if not endPos then return "" end
    end
    return content:sub(startPos, endPos)
end

-- 計算區段內特定欄位值的出現次數(用 {{!}}{{!}} 包夾精確比對)
local function countField(section, value)
    local n = 0
    local pattern = "%{%{!%}%}%{%{!%}%}%s*" .. value .. "%s*%{%{!%}%}%{%{!%}%}"
    for _ in section:gmatch(pattern) do n = n + 1 end
    return n
end

-- ============================================================
-- 正式邦交國(前一表格:無/頁面開頭,本表格 id=luminebang)
-- 欄位:序號 | 國旗及國名 | 建立外交關係時間 | 外交代表機構 | 詳見
-- ============================================================

function p.bangTotal(frame)
    return countBetween(getContent(), nil, ID_BANG)
end

function p.bangAmbassador(frame)
    return countField(getSection(getContent(), nil, ID_BANG), "大使")
end

function p.bangMinister(frame)
    return countField(getSection(getContent(), nil, ID_BANG), "公使")
end

function p.bangCharge(frame)
    return countField(getSection(getContent(), nil, ID_BANG), "代辦")
end

function p.bangNA(frame)
    return countField(getSection(getContent(), nil, ID_BANG), "不適用")
end

function p.bangFormal(frame)
    local s = getSection(getContent(), nil, ID_BANG)
    return countField(s, "大使") + countField(s, "公使") + countField(s, "代辦")
end

-- ============================================================
-- 經濟文化代表處(前:luminebang,本:luminejing)
-- 欄位:序號 | 國旗及國名 | 建立關係時間 | 外交代表機構 | 詳見
-- ============================================================

function p.jingTotal(frame)
    return countBetween(getContent(), ID_BANG, ID_JING)
end

-- ============================================================
-- 單方承認主權(前:luminejing,本:lumineunilateral)
-- 欄位:序號 | 國旗及國名 | 建立關係時間 | 外交代表機構 | 詳見
-- ============================================================

function p.uniTotal(frame)
    return countBetween(getContent(), ID_JING, ID_UNI)
end

-- ============================================================
-- 加入國際組織(前:lumineunilateral,本:lumineorg)
-- 欄位:序號 | 組織徽章及名稱 | 加入時間 | 組織內關係 | 詳見
-- ============================================================

function p.orgTotal(frame)
    return countBetween(getContent(), ID_UNI, ID_ORG)
end

-- ============================================================
-- 深度合作Discord組織(前:lumineorg,本:luminedc)
-- 欄位:序號 | 標誌及名稱 | 合作起始時間 | 詳見
-- ============================================================

function p.dcTotal(frame)
    return countBetween(getContent(), ID_ORG, ID_DC)
end

-- ============================================================
-- 同盟及合作協議(前:luminedc,本:luminetreaty)
-- 欄位:序號 | 締結條約 | 類型 | 締約成員 | 締約時間
-- ============================================================

function p.treatyTotal(frame)
    return countBetween(getContent(), ID_DC, ID_TREATY)
end

-- 含軍事性質的條約數(類型欄包含「軍事」)
function p.treatyMilitary(frame)
    local section = getSection(getContent(), ID_DC, ID_TREATY)
    local n = 0
    for _ in section:gmatch("%{%{!%}%}%{%{!%}%}[^%{]*軍事[^%{]*%{%{!%}%}%{%{!%}%}") do n = n + 1 end
    return n
end

-- 非軍事性質條約數
function p.treatyOther(frame)
    return (tonumber(p.treatyTotal(frame)) or 0) - (tonumber(p.treatyMilitary(frame)) or 0)
end

-- ============================================================
-- 歷史邦交國(前:luminetreaty,本:luminehistbang)
-- 欄位:序號 | 國旗及國名 | 建立外交關係時間 | 外交代表機構 | 斷交時間 | 斷交原因 | 詳見
-- 斷交原因:「亡國」/ 「併入[[XXX]]」/ 其他
-- ============================================================

function p.histTotal(frame)
    return countBetween(getContent(), ID_TREATY, ID_HIST)
end

function p.histExtinct(frame)
    return countField(getSection(getContent(), ID_TREATY, ID_HIST), "亡國")
end

function p.histMerged(frame)
    local section = getSection(getContent(), ID_TREATY, ID_HIST)
    local n = 0
    for _ in section:gmatch("%{%{!%}%}%{%{!%}%}%s*併入") do n = n + 1 end
    return n
end

function p.histOther(frame)
    return (tonumber(p.histTotal(frame)) or 0)
         - (tonumber(p.histExtinct(frame)) or 0)
         - (tonumber(p.histMerged(frame)) or 0)
end

-- ============================================================
-- 歷史參與國際組織(前:luminehistbang,本:luminehistorg)
-- 欄位:序號 | 組織徽章及名稱 | 加入時間 | 退出時間 | 退出原因 | 組織內關係 | 詳見
-- 退出原因:「組織解散」/ 其他(主動退出)
-- ============================================================

function p.histOrgTotal(frame)
    return countBetween(getContent(), ID_HIST, ID_HISTORG)
end

function p.histOrgDissolved(frame)
    return countField(getSection(getContent(), ID_HIST, ID_HISTORG), "組織解散")
end

function p.histOrgLeft(frame)
    return (tonumber(p.histOrgTotal(frame)) or 0) - (tonumber(p.histOrgDissolved(frame)) or 0)
end

-- ============================================================
-- 綜合統計
-- ============================================================

-- 邦交國+代表處+組織總計
function p.allTotal(frame)
    return (tonumber(p.bangTotal(frame)) or 0)
         + (tonumber(p.jingTotal(frame)) or 0)
         + (tonumber(p.orgTotal(frame)) or 0)
end

-- 曾建交總數(現有正式邦交國+歷史邦交國)
function p.everTotal(frame)
    return (tonumber(p.bangTotal(frame)) or 0)
         + (tonumber(p.histTotal(frame)) or 0)
end

function p.debug(frame)
    local c = getContent()
    local has_bang = c:find("id=luminebang") and "有" or "無"
    return "頁面長度:" .. #c .. " | luminebang:" .. has_bang
end

return p