For faster navigation, this Iframe is preloading the Wikiwand page for 模組:TemplateParameters.

模組:TemplateParameters

文档图示 模块文档[查看] [编辑] [历史] [清除缓存]

本模組可以將參數填入以普通模板參數定義的格式化字符串

設計緣由

自定義的模板參數讀取之構想早在2018年11月就已提出。當時數學類條目面臨大量WP:114.27的似是而非的破壞,不易查證真偽,因此建立了Module:Number(及複變部分的Module:Complex Number,如高斯整數分解)來自動計算並輸出數學性質,避免遭WP:114.27竄改為錯誤資訊而不易查證(例如多1少1的破壞難以察覺和驗證),但有用戶認為輸出固定字串無法被修改或添加註解、參考文獻不妥,因此出現了格式化字符串的需求,而部分用戶認為,應儘量是要設計一般維基人都能編輯的語法,因此最後決議選擇wikitext模板中的模板參數語法,但當時此功能獨自分散在各個需要格式化字符串功能的模組裡,例如Module:NumberModule:PeriodicTableModule:Delcat等地方。

最初的版本僅包含簡單文字替換,只能處理已知數量的參數,而在2019年6月,有用戶問到能否不寫新的模組、也不使用大量((#if:))實現,因此認為可以把自動讀取參數填入格式化字符串的功能獨立出來(即建立本模組),順便提供些特殊參數解析功能,如參數批次trim和數字解析功能(根據WP:TG1請求用於((Infobox 日本的町村)))。

使用說明

本模組主要是提供wikitext模板中的模板參數一個API,而非設計給其他Lua函數使用,因此專門給lua呼叫的函數較少。

本模組包括的函數如下:

用法

getFormatingStringByArgument

功能:直接將參數透過簡單文字替換填入形如(({X))}的位置內

  • ((#invoke:TemplateParameters | getFormatingStringByArgument | 在(({學科))}中,(({名稱))}是一種(({種類))} | 學科=數學 | 名稱=三角形 | 種類=多邊形))
    顯示為「在數學中,三角形是一種多邊形」
用途

FormatingArguments

功能:將未知數量的參數根據(({X))}規則依序填入給定的字符串中。

  • 模板中輸入
((#invoke:TemplateParameters|FormatingArguments|格式=這是第{\{\{1}\}\}個參數;|count=1|usingConditionalExpressions=yes))
  • 叫用模板((<模板名稱>|一|二|三|四))
  • 顯示為:「這是第一個參數;這是第二個參數;這是第三個參數;這是第四個參數;」
  • 解釋:
    • 模板中「格式」參數原本為這是第(({1))}個參數;,透過加入跳脫字元防止先被解析後,透過FormatingArguments函數將傳入模組讀所有參數依序填入,不必透過大量的((#if:(({N))}就能達成不定數量的參數傳遞。

  • 模板中輸入
((#invoke:TemplateParameters|FormatingArguments|格式=*:[[畢氏三元數]]:{\{#tag:math((!))\\left({\{\{1}\}\},{\{\{2}\}\} ,{\{\{3}\}\}\\right)}\}\n|count=3|usingConditionalExpressions=yes))
  • 叫用模板((<模板名稱>|3|4|5|5|12|13|7|24|25))
  • 顯示為:
    畢氏三元數
    畢氏三元數
    畢氏三元數
  • 解釋:
    • 模板中「格式」參數原本為*:[[畢氏三元數]]:((#tag:math|\left((({1))},(({2))} ,(({3))}\right)))\n
      指定了數量為3( | count=3)後,會將參數每三個一組代入(({1))}(({2))}(({3))}

格式字串中支援的參數

下面為FormatingArguments支援的參數,若有同名參數可能會影響運作

  • 讀取不定參數:
    • (({1))}(({2))}(({3))}...即以組為單位讀取不定參數。
      例如((|1|2|3|4|5|6|7|8|9))如果設定為每組3個參數,
      則第一組的(({1))}(({2))}(({3))}分別會代入1、2和3;
      第二組的(({1))}(({2))}(({3))}分別會代入4、5和6
      以此類推。
    • (({count+1))}(({count+2))}(({count+3))}...讀取下一組的不定參數。
      例如((|1|2|3|4|5|6|7|8|9))如果設定為每組3個參數,此時(({count+1))}即為(({4))}
      則第一組的(({4))}(({5))}(({6))}分別會代入4、5和6;
      則第二組的(({4))}(({5))}(({6))}分別會代入7、8和9;
      則第三組的(({4))}(({5))}(({6))}因為沒有第四組,而會變成空值、預設參數或保持原樣(即(({4))});
    • (({0))}(({-1))}(({-2))}...讀取前一組的不定參數。
      例如((|1|2|3|4|5|6|7|8|9))如果設定為每組3個參數
      則第一組的(({0))}(({-1))}(({-2))}因為第一組沒有前一組,而會變成空值、預設參數或保持原樣(即(({0))});
      則第二組的(({0))}(({-1))}(({-2))}分別會代入3、2和1;
      則第三組的(({0))}(({-1))}(({-2))}分別會代入6、5和4;
      以此類推。
    • (({random))}:位於本組的隨機參數。
    • (({allRandom))}:所有參數的隨機參數。
    • (({last))}:本組的最後一個參數。
  • 判斷用參數
    • (({isFirst))}:如果這是第一組參數則為1,否則為空值
    • (({isLast))}:如果這是最後一組參數則為1,否則為空值
    • (({count))}:參數組的數量。
    • (({argGroupID))}:返回目前作用中的參數是第幾組。

Subst方法

此模板可以使用Subst,不過若用<nowiki></nowiki>搭配 | delnowiki = 參數的話會導致替換失敗。

  • 替代方案可以使用跳脫字元(如\{\}等)以及H:魔術字(如((!))(( (({|safesubst:))}!))(([[Template:|]]))(( (({|safesubst:))}=))等)
  • 若覺得編輯困難可以使用 子頁面搭配((msgnw:模板名))以及 | delmsgnw = 參數 來完成
    • 詳細使用方式可參考User:A2569875/SubstTest搭配User:A2569875/SubstTest/Cell的範例。
    • 使用((msgnw:模板名))需要(※)注意的是:由於使用msgnw,因此<noinclude></noinclude>等標記無效,因此不應該在該子模板中直接加入註解或((Doc))的內容,需要使用((ifsubst))才能運作,例如(( (({|safesubst:))}ifsubst||<noinclude>((documentation))</noinclude>))
      或者:
(( (({|safesubst:))}ifsubst||<noinclude>
不被包含引用的部分
</noinclude>))

containsNumber

功能:用於確定一個參數內是否有包含阿拉伯數字

  • ((#invoke:TemplateParameters|containsNumber|hijk42lm))→「1」
  • ((#invoke:TemplateParameters|containsNumber|hijklm))→「」

用法

  • ((#if:((#invoke:TemplateParameters|containsNumber|hijk42lm))|有數字|沒數字))→「有數字」
  • ((#if:((#invoke:TemplateParameters|containsNumber|hijklm))|有數字|沒數字))→「沒數字」

getNumberValue

功能:嘗試從一個參數內讀出一個阿拉伯數字,若讀不出來,則傳回0

  • ((#invoke:TemplateParameters|getNumberValue|hijk42lm))→「42」
  • ((#invoke:TemplateParameters|getNumberValue|hijklm))→「0」

用法

  • ((#expr: hijk42lm ))→「表达式错误:无法识别词语“hijk”。
  • ((#expr:((#invoke:TemplateParameters|getNumberValue|hijk42lm)) ))→「42」
  • ((#expr:hijklm ))→「表达式错误:无法识别词语“hijklm”。
  • ((#expr:((#invoke:TemplateParameters|getNumberValue|hijklm)) ))→「0」

arg_to_spstr與pass_spstr

功能:arg_to_spstr會將參數轉變成一個可供pass_spstr使用的字串;pass_spstr可以將arg_to_spstr給出的參數套入模板語法

設計動機:批次大量傳送參數的方案
((#invoke:TemplateParameters|pass_spstr
 | code = (({1))}((2))(({3))}
 | args = ((#invoke:TemplateParameters|arg_to_spstr|A|B|C))
))
顯示為「A-B-C」

argTrim

功能:適用於本系列模板的trim方案(delnowiki可正常使用((trim))),((trim))會導致使用「((!))」的後方內容被捨棄

  • 一般Trim
    • 模板內容((#invoke:TemplateParameters|FormatingArguments|格式=[\[:{\{Trim((!)) {\{\{1}\}\} }\}]\]|count=1|usingConditionalExpressions=yes))
    • 叫用模板((<模板名稱>|一((!))遺失的內容))
    • 顯示為:「
  • 一般Trim + delnowiki
    • 模板內容((#invoke:TemplateParameters|FormatingArguments|格式=<nowiki>[[:((Trim| (({1))} ))]]</nowiki>|delnowiki=1|count=1|usingConditionalExpressions=yes))
    • 叫用模板((<模板名稱>|一((!))遺失的內容))
    • 顯示為:「遺失的內容
  • 使用argTrim
    • 模板內容((#invoke:TemplateParameters|FormatingArguments|格式=[\[:(((())#invoke:TemplateParameters((!))argTrim((!))(({1))} (())))]\]|count=1|usingConditionalExpressions=yes))
    • 叫用模板((<模板名稱>|一((!))遺失的內容))
    • 顯示為:「遺失的內容
  • 使用argTrim + delnowiki
    • 模板內容((#invoke:TemplateParameters|FormatingArguments|格式=<nowiki>[[:((#invoke:TemplateParameters|argTrim|(({1))} ))]]</nowiki>[\[:{\{#invoke:TemplateParameters((!))argTrim((!))(({1))} }\}]\]|count=1|usingConditionalExpressions=yes))
    • 叫用模板((<模板名稱>|一((!))遺失的內容))
    • 顯示為:「遺失的內容

listArguments

功能:列出模板接收到的參數

用途:偵錯用

  • 輸入((#invoke:TemplateParameters|listArguments|A|B|C|99=D|E=F))
  • 顯示為:
  • ((#invoke:))呼叫參數:
    1 : A
    2 : B
    3 : C
    99 : D
    E : F

call

功能:將模板參數轉為Lua參數的方法,提供呼叫一些不支援以模板參數呼叫之Module。

用途:能讓一些未提供模板參數呼叫之Module在不建立新Module的情況下由模板調用。

例如Module:yesno目前暫未支援由模板直接調用。
  • 輸入((#invoke:TemplateParameters|call|Module:yesno|T))
  • 顯示為:「1」(參見下方#回傳值子章節)

參數

  • 第一參數為模板與模組名稱,以點「 . 」運算子來從模組中獲得函數名稱,如「Module:Foo.bar」指的是Module:Foo中的function bar( ),需要注意的是,為了提升效能,因此判斷是用簡單的字串分割達成,因此若模組名稱含有點「 . 」符號,則無法使用此功能。
  • 其他參數則會依序傳入指定的模組函數中

回傳值

  • 若模組回傳值為數字字串,則會直接顯示結果;
  • 若模組回傳值為布林值則:true以「1」表示,否則輸出空字串。這是為了讓結果能給((#if:))使用
  • 若模組沒有回傳值則輸出空字串;
  • 若模組回傳值為其他物件,則會嘗試將物件轉為JSON後輸出。此步驟有可能因為物件中包含了無法JSON化的物件導致失敗。

選項

  • | isJSON = :將所有輸入參數視為JSON
    部分模組中函數可能有需要傳入特殊格式物件的需求,此時可以透過設定此選項來以JSON來輸入支援的物件。

注意事項:若指定的模組中函數本身已支援模板調用則可能出錯。因為支援模板調用的模組通常是用第一參數接收所有模板參數,而此函數會先將模板參數全部展開才傳入,可能會有參數無效或者第一參數無法使用(如支援模板調用的第一參數預期是一個包含所有模板參數資訊的lua table,但本函數將參數展開可能導致第一參數變為字符串或數字)等問題。

templateArgWarp

功能:替換引用時,將自身替換為另一個模板與參數

用途:如防止替換引用(替換引用又換回自身)或替換引用時轉成其他等價模板等。

參數:第一參數為要替換成的模板名稱。只有第一參數有效,其餘參數皆為從父模板讀取。

makeTemplateParameter

功能:產生模板參數的未解析字串,如(({arg))}

用途:搭配((虛擬模板))作為替換引用的替代方案,參見((參數))。

  • 輸入((#invoke:TemplateParameters|makeTemplateParameter|arg|default))
  • 顯示為:「(({arg|default))}」

用途

相關模板

local p = {}
local lib_arg = {}
local yesno = {}
local lib_editstate={};
function p.containsNumber(frame)
	-- For calling from #invoke.
    local args
    local can_call_parse = false
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        args = frame.args
        can_call_parse = true
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        if type(args) ~= type({}) then args = {frame} end
    end
    local input_str=mw.ustring.gsub(args[1] or args['1'],',','')
    local g0=mw.ustring.gmatch(input_str,"[%+%-]?[0-9%.]+e[%+%-]?[0-9%.]+")
    local out_str = nil
    if g0 then out_str = g0() end
    if (out_str or '') == '' then 
    	g0=mw.ustring.gmatch(input_str,"[%+%-]?[0-9%.]+") 
    else
    	return '1'
    end
    if g0() then return '1' end
    return ''
end

function p.getNumberValue(frame)
	-- For calling from #invoke.
    local args
    local can_call_parse = false
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        args = frame.args
        can_call_parse = true
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        if type(args) ~= type({}) then args = {frame} end
    end
    local input_str=mw.ustring.gsub(args[1] or args['1'],',','')
    local g0=mw.ustring.gmatch(input_str,"[%+%-]?[0-9%.]+e[%+%-]?[0-9%.]+")
    local out_str = nil
    if g0 then out_str = g0() end
    if (out_str or '') == '' then 
    	g0=mw.ustring.gmatch(input_str,"[%+%-]?[0-9%.]+") 
    else
    	return out_str
    end
    return g0() or '0'
end

function p.argTrim(frame)
	-- For calling from #invoke.
    local args
    local can_call_parse = false
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        args = frame.args
        can_call_parse = true
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        if type(args) ~= type({}) then args = {frame} end
    end
    local arg_counts = 1
    local input_str = ''
    local first_str = ''
    local one_str = mw.text.trim(args['1'] or args[1] or '')
    local count = 0
    local pipe_to_magic_word = false
    if (args["pipe"] or '') ~= '' then
		if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
		pipe_to_magic_word = yesno(args["pipe"] or 'no')
	end
	local num_arg_count = 0
	local first_arg = true
	for id,_ in pairs(args) do if (tonumber(id) or 0) > num_arg_count then num_arg_count = tonumber(id) or 0 end end
	for id=1,num_arg_count do 
    	local it_str = mw.text.trim(args[tostring(id)] or args[id] or '')
    	if pipe_to_magic_word then it_str = mw.ustring.gsub(it_str,"%|", "((!))") end
    	if not first_arg then input_str = input_str .. '|' else first_arg = false end
    	input_str = input_str .. it_str
    	if first_str == '' then first_str = it_str end
    	if it_str~='' then count = count+1 end
	end
    for key,val in pairs(args) do
    	local it_str = mw.text.trim(val)
    	if pipe_to_magic_word then it_str = mw.ustring.gsub(it_str,"%|", "((!))") end
    	if (tonumber(key) or 0) < 1 and it_str~='' and mw.text.trim(tostring(key)) ~= 'pipe' then 
    		if input_str ~= '' then input_str = input_str .. '|' end
    		input_str = input_str .. mw.text.trim(tostring(key)) .. '=' .. it_str
    		if first_str == '' then first_str = it_str end
    		count = count+1
    	end
    end
    if count > 1 then return mw.text.trim(input_str)
    else 
    	if one_str~='' then return first_str
    	else return mw.text.trim(input_str) end
    end
end

function p.listArguments(frame)
	local body = ''
	function print_args(farg, str)
		local body = ''
		local flag = false
		if farg.args then
			body = body .. '*' .. "((" .. (str or farg:getTitle())  .. "))呼叫參數:" .. '\n'
			for k,v in pairs(farg.args) do
				if(type(v) ~= type(tonumber) and type(v) ~= type({}))then
					flag = true
					body = body .. '*:' .. "'''" .. k .. "''' : " .. tostring(v) .. '\n'
				end
			end
		end
		if flag then return body else return '' end
	end
	if frame ~= mw.getCurrentFrame() and type(frame) == type({}) then
		body = body .. '*' .. "函數呼叫參數:" .. '\n'
		for k,v in pairs(frame) do
			body = body .. '*:' .. "'''" .. k .. "''' : " .. v .. '\n'
		end
	end
	local this_arg = frame.args
	if type(this_arg) == type({}) then body = body .. print_args(frame, "#invoke:") end
	local iter = mw.getCurrentFrame()
	if iter == frame then iter = mw.getCurrentFrame():getParent() end
	while iter do
		body = body .. print_args(iter)
		iter = iter:getParent()
	end
	return body
end
local argument_check = false
function p.checkArgument(frame)
	argument_check = true
	return p.getParentArgument(frame)
end

function p.makeTemplateParameter(frame)  --產生模板參數字串
	local args, working_frame
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        args = {}
        for key,value in frame:argumentPairs() do
        	args[key] = value or ''
        end
        local Parent = frame:getParent();
        if Parent then for key,value in Parent:argumentPairs() do
        	args[key] = args[key] or value or ''end 
    	end
        working_frame = frame
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        working_frame = mw.getCurrentFrame()
        if type(args) ~= type({}) then args = {frame} end
    end
    local argname = args[1] or args['1'] or args['name']
    local argDefault = args[2] or args['2'] or args['default']
    local default_text = ''
    if argname then
    	argname = mw.text.trim(argname or '')
    	if argDefault then
    		default_text = '|' .. mw.text.trim(argDefault or '')
    	end
    else
    	argname, default_text = '', '|' .. mw.text.trim(argDefault or '')
    end
    if mw.text.trim(argname .. default_text) == '' then return '' end
    local result = '(({' .. argname .. default_text .. '))}'
    if args[4] or args['4'] then return result end
    if type(lib_editstate.isPreview) ~= type(tonumber) then lib_editstate = require('Module:EditState') end
    if ((mw.isSubsting() or lib_editstate.isPreview()) and (args[3] or args['3'])) then
    	if working_frame:getParent() then return working_frame:getParent():preprocess(result) end
    end
    return result
end

function p.call(frame) --轉換模板參數為lua參數
	local args, working_frame
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        if lib_arg.getArgs == nil then lib_arg = require('Module:Arguments') end
        args = lib_arg.getArgs(frame, {parentFirst=true})
        working_frame = frame
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        working_frame = mw.getCurrentFrame()
        if type(args) ~= type({}) then args = {frame} end
    end
    local max_arg = 0 
    local num_args = {}
    local isJSON = false
    if args.isJSON then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
    	if yesno(args.isJSON or 'no') then --local delnowiki=require('Module:Delcat').delnowiki --備用
			isJSON = true
		end
	end
	for key,value in pairs( args ) do
		local arg_id = tonumber(key or '')
		if arg_id then
			if arg_id > max_arg then max_arg = arg_id end
			num_args[arg_id] = value
		end
	end
	local func_name = num_args[1]
	if mw.text.trim(func_name or '') == '' then return '' end
	local call_args = {}
	local get_obj = function(obj)return obj end
	if isJSON then get_obj = function(obj)return mw.text.jsonDecode(obj)end end
	if max_arg > 1 then
		for i = 2,max_arg do
			if num_args[i] then 
				local try_to_get_obj = mw.clone(num_args[i])
				if not xpcall( function() --try
					try_to_get_obj = get_obj(num_args[i])
				end, function(msg)return msg end ) then --catch
					call_args[i-1] = num_args[i]
				else --finally
					call_args[i-1] = try_to_get_obj
				end
			else call_args[i-1] = '' end
		end
	end

	local func_path = mw.text.split(func_name,'%.') or { [1]=func_name }
	local func_body = mw[func_path[1]] or p[func_path[1]] or _G[func_path[1]]
	if mw.ustring.find(func_path[1],':') then
		func_body = require(func_path[1]) or func_body
	end
	if func_body then
		local old_obj = func_body
		for i=2,#func_path do
			func_body = func_body[func_path[i]]
			if func_body then
				old_obj = func_body
			else
				return ''
			end
		end
		local func_type = type( func_body )
		local times = 10
		for ti = 1,times do
			if func_type == type(nil) then
				return ''
			elseif func_type == type(0) then
				return '' .. func_body
			elseif func_type == type(true) then
				if func_body then return '1' end
				return ''
			elseif func_type == type(type) then
				if max_arg > 1 then 
					func_body = func_body(unpack(call_args))
					if func_body == nil then func_body = call_args[1] end
				else func_body = func_body() end
			elseif func_type == type("string") then
				return func_body
			elseif func_type == type({}) then
				return mw.text.jsonEncode(func_body)
			end
			func_type = type( func_body )
		end
	end
	return ''
end

function p.getParentArgument(frame)
	local this_arg = frame.args
	local check_if = this_arg['if'] or this_arg['if value'] or this_arg.if_value or ''
	if mw.ustring.find(check_if,'%[%[') then check_if=require('Module:Delcat').delete_category(check_if, {}) end
	if mw.text.trim(check_if) ~= '' then return check_if end
	local out_arg = mw.getCurrentFrame():getParent().args
	if tonumber(this_arg.out or 1) > 1 then
		local iter = mw.getCurrentFrame()
		for i=1,tonumber(this_arg.out) do
			if iter:getParent() then
				iter = iter:getParent()
			end
		end
		if iter.args then out_arg=iter.args end
	end
	local result = ''
	local is_used = false
	if this_arg.name and out_arg then
		if out_arg[this_arg.name] then 
			if result ~= '' and result ~= out_arg[this_arg.name] then is_used =true end
			result = out_arg[this_arg.name] 
		end
	end
	if out_arg then
		for k,v in ipairs(this_arg) do
			if out_arg[v] then 
				if result ~= '' and result ~= out_arg[v] then is_used =true end
				result = out_arg[v] 
			end
		end
	end
	if mw.getCurrentFrame():getParent() then
		if argument_check then argument_check = false else
			if is_used then mw.addWarning( mw.getCurrentFrame():getParent():getTitle() .. "中,參數 \""
				.. (this_arg.name or this_arg[1]) ..  "\" 被用不同的內容定義了多次。"  ) end
		end
	end
	if result == '' then return this_arg.value or this_arg['if value'] or this_arg.if_value or '' end
	return result
end

function getMaxArgCount(out_args, max_count, prefixs)
	for index, arg_val in pairs(out_args) do 
		local start_id, end_id = mw.ustring.find(index,'%d+$')
		if start_id then
			local index_name = mw.text.trim(mw.ustring.sub(index, 1, start_id-1))
			local index_num = mw.ustring.sub(index, start_id, end_id)
			for ____,prefix in pairs(prefixs) do 
				if mw.text.trim(prefix) == index_name then
					if (tonumber(index_num) or 0) > max_count then 
						max_count = (tonumber(index_num) or 0) 
					end
					break
				end
			end
		end
	end
	return max_count
end

--外部讀取不定參數
function p.FormatingArguments(frame)
	-- For calling from #invoke.
    local args
    --是否存在有效的frame可供呼叫
    local can_call_parse = false
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        args = frame.args
        can_call_parse = true
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
    end
    local input_str = '' --輸入的格式化字串
    local count = 1 --預設參數數量為1個一組
    if args["format"] or args["Format"] or args["格式"] then input_str = args["format"] or args["Format"] or args["格式"] or '' end
    if args["count"] then count = tonumber(args["count"] or 1) or 1 end
    local display_all = false --是否顯示跳過的參數 (如輸入1,2,5參數,決定是否輸出3,4參數)
    local delnowiki = false --是否從nowiki中解除包裝
    local hasPrefixArg = false 
    local arrPrefixArg = {}
    local allexpr = false --是否每組參數全部都呼叫一次帶參數的新解析器 (高開銷,最多100次)
    local allexpr_count = 1 --紀錄呼叫帶參數的新解析器次數,以免超過100次lua停止運作
    if args["displayAll"] then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
		display_all = yesno(args["displayAll"] or 'no')
	end
    if args["PrefixArgs"] then
	    if args["hasPrefixArg"] then
	    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
			hasPrefixArg = yesno(args["hasPrefixArg"] or 'no')
			arrPrefixArg = mw.text.split(args["PrefixArgs"] or '',',');
		end 
	end

    if args["delnowiki"] then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
    	if yesno(args["delnowiki"] or 'no') then --local delnowiki=require('Module:Delcat').delnowiki --備用
			input_str = mw.text.unstripNoWiki( input_str )
		end
	end
	if args["delmsgnw"] then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
    	if yesno(args["delmsgnw"] or 'no') then 
			input_str = mw.text.decode( input_str )
		end
	end
    if args["allexpr"] then --較耗費資源
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
		allexpr = yesno(args["allexpr"] or 'no')
	end
    count = math.floor(count) --不處理小數
    if count < 1 then count = 1 end --非正整數當作1
    
    local other_num_args = {} --紀錄範圍外參數
    if args["checkMoreArg"] then --處理範圍外參數 (如已定義每組3參數,但想用(({4))}存取下一組的第一參數)
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
    	if yesno(args["checkMoreArg"] or 'no') then --較耗費資源
			local allnumarg_checker = mw.ustring.gmatch(input_str,"%{%{%{[^%{%}%|]+[%}%|]")
			local pre_arg_str = allnumarg_checker() --匹配模板參數
			local find_num_args = {}
			while(pre_arg_str) do
				local arg_name_str = mw.ustring.gsub(pre_arg_str,"[^%d%l%u%+%-%.]",'')
				local arg_name_num = tonumber(arg_name_str)
				if arg_name_num then
					find_num_args[arg_name_num] = true
				end
				pre_arg_str = allnumarg_checker()
			end
			for check_is_other_num_args, _ in pairs(find_num_args) do --紀錄範圍外參數
				if check_is_other_num_args > count or check_is_other_num_args < 1 then
					other_num_args[#other_num_args + 1] = check_is_other_num_args
				end
			end
		end
	end

    local usingConditionalExpressions = false --是否額外再呼叫解析器函數
    if args.usingConditionalExpressions then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
    	if yesno(args.usingConditionalExpressions) == true and can_call_parse then
    		usingConditionalExpressions = true
    		input_str = p._get_escape(input_str)
    	end
    end
    local out_frame = mw.getCurrentFrame():getParent() --模板外層
    local out_args = {} --紀錄來自模板外層提供的參數
    local body = ''
    if out_frame then out_args = out_frame.args or out_args end
    
	local valueTable = {} --紀錄可用值 (參數) 提供填入參數之用
    local max_count, i, j = 1, 0, 0 for index, arg_val in pairs(out_args) do if (tonumber(index) or 0) > max_count then max_count = (tonumber(index) or 0) end valueTable[#valueTable + 1] = arg_val end
    max_count = math.ceil(max_count / count); --獲輸入參數之最大數量 (以組為單位)
    
    if hasPrefixArg then max_count = getMaxArgCount(out_args, max_count, arrPrefixArg) end

    local last_one = false
    for i = 1, max_count do
    	local local_arg = {} --紀錄本組的參數
    	local_arg.isLast, local_arg["isFirst"]= '', '' --提供判斷的魔術參數
    	local_arg.count=tostring(max_count)
    	local_arg.argGroupID = tostring(i)
    	local_arg.last = out_args[tostring(i * count)] or out_args[i * count] or args[tostring(count)] or args[count]
    	if local_arg.last == nil and not allexpr then local_arg.last=('(({' .. tostring(count) .. '))}') end
    	if i == max_count then local_arg["isLast"] = '1' end
    	if i == 1 then local_arg["isFirst"] = '1' end
		if allexpr and allexpr_count > 99 then
		 	allexpr = false  --紀錄呼叫帶參數的新解析器次數,超過100次停止運作,改用純字串替換完成輸出
		    mw.addWarning( "指定 \"allexpr\" 參數全部展開已超過展開上限,後面的參數將使用低消耗函式填入數值。" )
		end
    	if(#valueTable > 1) then --提供部分須輪播展示的參數組
			local_arg.allRandom = valueTable[math.random( 1, #valueTable )]
			local rand_local = math.random(1, count)
			local rand_it = (i-1) * count + rand_local --查無參數則從外層抓
	   		local_arg.random = out_args[tostring(rand_it)] or out_args[rand_it] or args[tostring(rand_local)] or args[rand_local]
	    		if local_arg.random == nil and not allexpr then local_arg.random=('(({' .. tostring(rand_local) .. '))}') end
    	end
    	local is_ready = false --本組參數是否有值
    	for j = 1, count do
    		local it = (i-1) * count + j
    		local_arg.ArgID = tostring(it)
    		local_arg[j] = out_args[tostring(it)] or out_args[it] or args[tostring(j)] or args[j]
    		if local_arg[j] == nil and not allexpr then local_arg[j]=('(({' .. tostring(j) .. '))}') end
    		--找到本組參數的其中一個值
    		if out_args[tostring(it)] or out_args[it] then is_ready = true end
    	end
    	
    	if hasPrefixArg then local_arg, is_ready = addPrefixArgToArgList(out_args, args, local_arg, tostring(i), arrPrefixArg, allexpr, is_ready) end
    	
    	for _, other_arg_it in ipairs(other_num_args) do --處理範圍外參數
    		local it = (i-1) * count + other_arg_it
    		local_arg[other_arg_it] = out_args[tostring(it)] or out_args[it] or args[tostring(other_arg_it)] or args[other_arg_it]
    		if local_arg[other_arg_it] == nil and not allexpr then local_arg[other_arg_it]=('(({' .. tostring(other_arg_it) .. '))}') end
    	end
	    if is_ready or display_all then --本組參數有值存在才輸出; 如果設定全部顯示也顯示
		    local output_str = tostring(input_str)
		    if allexpr then 
				for org_arg, org_arg_val in pairs(args) do
					if (local_arg[org_arg] or '') == '' then local_arg[org_arg] = org_arg_val end
				end
		    	local working_frame = frame:newChild{ title = frame:getTitle(), args = local_arg }
		    	body=body..working_frame:preprocess( output_str ) --呼叫帶參數的新解析器
		    	allexpr_count=allexpr_count+1
			else
				body=body..p._getFormatingStringByArgument(output_str, local_arg) --使用一般字串取代填入參數
		    end
		    
	   	end
	end

	if usingConditionalExpressions and can_call_parse then
    	body = frame:preprocess( body )
    end
    return body
end

--內部讀取確定參數
function p.getFormatingStringByArgument(frame)
	-- For calling from #invoke.
    local args
    local can_call_parse = false
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        if lib_arg.getArgs == nil then lib_arg = require('Module:Arguments') end
        args = lib_arg.getArgs(frame) --frame.args
        can_call_parse = true
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
    end
    local targs = {}
    for arg, val in pairs(args) do
    	if tonumber(arg) ~= 1 then
    		targs[arg] = val
    	end
    end
    local input_str = args[1] or args['1']
    local usingConditionalExpressions = false
    if args.usingConditionalExpressions then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
    	if yesno(args.usingConditionalExpressions) == true and can_call_parse then
    		usingConditionalExpressions = true
    		input_str = p._get_escape(input_str)
    	end
    end
    local output_str = p._getFormatingStringByArgument(input_str, targs)
    if usingConditionalExpressions and can_call_parse then
    	output_str = frame:preprocess( output_str )
    end
    return output_str
end

function p._findNullArgument(str, args)
	local result = str or "*(({1))}\n"
	local emptylist = {}
	for k,v in pairs(args) do
		local ke = p._getEscapeString(k)
		local pattern = "%{%{%{%s*".. ke .. "%s*%}%}%}"
		if mw.ustring.find(result, pattern) then
			if string.gsub(string.gsub(v or '' , ' ', "") , "%s$", "") == '' then emptylist[k] = true end
		else emptylist[k] = true end
		result = mw.ustring.gsub(result, pattern, tostring(args[k]) )
	end
	return emptylist
end

--格式化字串的處理,會將特殊的 (({))} 轉換
function p._getEscapeString(str) str = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(str, "%%", "%%%%"), "%]", "%]"), "%{", "%{"), "%}", "%}"), "%[", "%["), "%)", "%)"), "%-", "%-"), "%^", "%^"), "%$", "%$"), "%(", "%("), "%.", "%."), "%*", "%*"), "%+", "%+"), "%|", "%|"); return str; end function p._getFormatingStringByArgument(str, args)
	local result = str or "*(({1))}\n"
	for k,v in pairs(args) do
		local ke = p._getEscapeString(k)
		result = mw.ustring.gsub(result, "%{%{%{%s*".. ke .. "%s*%}%}%}", tostring(args[k]) )
	end
	return result
end

function p._get_escape(str)
 	local escapestrs = mw.text.split( str, '\\\\')
 	local escapechars = (("\\n", "\n"},{"\\r", "\r"},{"\\t", "\t"},{"\\b", "\b"},{"\\f", "\f"},{"\\v", "\v"},{"\\", ""},}
 	for i,text in pairs(escapestrs) do 
 		for _, escape_result in ipairs(escapechars) do
 			escapestrs[i] = mw.ustring.gsub(escapestrs[i], escape_result[1], escape_result[2])
 		end
 	end
 	return table.concat(escapestrs, '\\')
end

function p.arg_to_spstr(frame)
	-- For calling from #invoke.
    local args
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        if lib_arg.getArgs == nil then lib_arg = require('Module:Arguments') end
        args = lib_arg.getArgs(frame)
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        if type(frame) ~= type({}) then args = {frame} end
    end
    body=''
    for k,v in pairs(args) do
		body = body .. "<參數分隔/>" .. k .. "<參數值/>" .. v
	end
	return body
end

function p.pass_spstr(frame)
	-- For calling from #invoke.
    local args
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        if lib_arg.getArgs == nil then lib_arg = require('Module:Arguments') end
        args = lib_arg.getArgs(frame) --frame.args
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        if type(frame) ~= type({}) then args = {frame}
        else args = frame end
    end
    local input_text = args['code'] or ''
    if args["delnowiki"] then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
    	if yesno(args["delnowiki"] or 'no') then --local delnowiki=require('Module:Delcat').delnowiki --備用
			input_text = mw.text.unstripNoWiki( input_text )
		end
	end
	if args["delmsgnw"] then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
    	if yesno(args["delmsgnw"] or 'no') then 
			input_text = mw.text.decode( input_text )
		end
	end
    local input_text = p._get_escape(input_text)
    local input_args = { text = input_text }
    local input_title = args['TemplateTitle']
    local spilt_args = mw.text.split( args['args'] or '', '<參數分隔/>')
    local working_frame = frame
	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
	local child_args = {}
	for aname, aval in pairs(args) do child_args[aname] = aval end
    if yesno(args.useParent or 'no') == true then 
    	working_frame = frame:getParent() or frame 
    	for aname, aval in pairs(working_frame.args) do child_args[aname] = aval end
    end
    for _,v in ipairs(spilt_args) do
    	local text = mw.text.trim(v)
    	if text ~= '' then
    		local spilt_kv = mw.text.split( text, '<參數值/>')
    		local key = mw.text.trim(spilt_kv[1])
    		local nkey = tonumber(key)
    		if key ~= '' then input_args[key],child_args[key] = spilt_kv[2],spilt_kv[2] end
    		--if nkey ~= nil then input_args[nkey],child_args[nkey] = spilt_kv[2],spilt_kv[2] end
    	end
    end
    working_frame = working_frame:newChild{ title = input_title or working_frame:getTitle(), args = child_args }
	return working_frame:preprocess(input_args)
end

function addPrefixArgToArgList(in_arg1, in_arg2, out_args, item_id, prefixs, allexpr, is_ready)
	for ____,prefix in pairs(prefixs) do 
		local argName = prefix .. item_id
		out_args[prefix] = in_arg1[argName] or in_arg2[argName]
		if out_args[prefix] then is_ready = true end
		if out_args[prefix] == nil and not allexpr then out_args[prefix]=('(({' .. prefix .. '))}') end
	end
	return out_args, is_ready
end

function p.templateArgWarp(frame, warpargs)
	local args, new_name
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        new_name = frame.args['1'] or frame.args[1] or frame.args.name or frame.args.Name
        local parent = frame:getParent() or {['args']={))
        args = parent.args
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        if type(frame) == type('string') then new_name = frame
        elseif type(frame) == type({}) then new_name = frame['1'] or frame[1] or frame.name or frame.Name
        end
        args = warpargs or mw.getCurrentFrame().args
    end
    local result = require('Module:Template invocation').invocation(new_name, args)
    local args_other = mw.getCurrentFrame().args.args
    if args_other then result = mw.ustring.gsub(mw.text.trim(result),"))$",'') .. '|' .. args_other .. "))" end
    if mw.getCurrentFrame().args["preprocess"] then
    	if type(yesno) ~= type(tonumber) then yesno = require('Module:Yesno') end
    	if yesno(mw.getCurrentFrame().args["preprocess"] or 'no') then
			return mw.getCurrentFrame():preprocess(result)
		end
	end
	return result
end

return p
{{bottomLinkPreText}} {{bottomLinkText}}
模組:TemplateParameters
Listen to this article

This browser is not supported by Wikiwand :(
Wikiwand requires a browser with modern capabilities in order to provide you with the best reading experience.
Please download and use one of the following browsers:

This article was just edited, click to reload
This article has been deleted on Wikipedia (Why?)

Back to homepage

Please click Add in the dialog above
Please click Allow in the top-left corner,
then click Install Now in the dialog
Please click Open in the download dialog,
then click Install
Please click the "Downloads" icon in the Safari toolbar, open the first download in the list,
then click Install
{{::$root.activation.text}}

Install Wikiwand

Install on Chrome Install on Firefox
Don't forget to rate us

Tell your friends about Wikiwand!

Gmail Facebook Twitter Link

Enjoying Wikiwand?

Tell your friends and spread the love:
Share on Gmail Share on Facebook Share on Twitter Share on Buffer

Our magic isn't perfect

You can help our automatic cover photo selection by reporting an unsuitable photo.

This photo is visually disturbing This photo is not a good choice

Thank you for helping!


Your input will affect cover photo selection, along with input from other users.

X

Get ready for Wikiwand 2.0 🎉! the new version arrives on September 1st! Don't want to wait?