Module:Transcluder more
模块文档[创建]
您可能想要创建本Scribunto模块的文档。 编者可以在本模块的沙盒 (创建 | 镜像)和测试样例 (创建)页面进行实验。 请在/doc子页面中添加分类。 本模块的子页面。 |
-- Provide more transclusion funtions
-- Modified from Module:Transcluder: https://en.wikipedia.org/wiki/Module:Transcluder
-- Authors of Module:Transcluder: User:Sophivorus, User:Certes & others
-- License of Module:Transcluder: CC-BY-SA-3.0
local p = {}
-- Helper function to test for truthy and falsy values
-- @todo Somehow internationalize it
local function truthy(value)
if not value or value == '' or value == 0 or value == '0' or value == 'false' or value == 'no' or value == 'non' then
return false
end
return true
end
-- Helper function to convert a comma-separated list of numbers or min-max ranges into a list of booleans
-- @param flags Comma-separated list of numbers or min-max ranges, for example '1,3-5'
-- @return Map from integers to booleans, for example {1=true,2=false,3=true,4=true,5=true}
-- @return Boolean indicating whether the flags should be treated as a blacklist or not
local function parseFlags(value)
local flags = {}
local blacklist = false
if not value then return nil, false end
if type(value) == 'number' then
if value < 0 then
value = -value
blacklist = true
end
flags = { [value] = true }
elseif type(value) == 'string' then
if string.sub(value, 1, 1) == '-' then
blacklist = true
value = string.sub(value, 2)
end
local ranges = mw.text.split(value, ',') -- split ranges: '1,3-5' to {'1','3-5'}
for _, range in pairs(ranges) do
range = mw.text.trim(range)
local min, max = mw.ustring.match(range, '^(%d+)%s*[-–—]%s*(%d+)$') -- '3-5' to min=3 max=5
if not max then min, max = string.match(range, '^((%d+))$') end -- '1' to min=1 max=1
if max then
for i = min, max do flags[i] = true end
else
flags[range] = true -- if we reach this point, the string had the form 'a,b,c' rather than '1,2,3'
end
end
-- List has the form { [1] = false, [2] = true, ['c'] = false }
-- Convert it to { [1] = true, [2] = true, ['c'] = true }
-- But if ANY value is set to false, treat the list as a blacklist
elseif type(value) == 'table' then
for i, v in pairs(value) do
if v == false then blacklist = true end
flags[i] = true
end
end
return flags, blacklist
end
-- Helper function to see if a value matches any of the given flags
local function matchFlag(value, flags)
if not value then return false end
value = tostring(value)
local lang = mw.language.getContentLanguage()
local lcvalue = lang:lcfirst(value)
local ucvalue = lang:ucfirst(value)
for flag in pairs(flags) do
if value == tostring(flag)
or lcvalue == flag
or ucvalue == flag
or ( not tonumber(flag) and mw.ustring.match(value, flag) ) then
return true
end
end
end
-- Helper function to remove a string from a text
local function removeString(text, str)
local pattern = escapeString(str)
if #pattern > 9999 then -- strings longer than 10000 bytes can't be put into regexes
pattern = escapeString(mw.ustring.sub(str, 1, 999)) .. '.-' .. escapeString(mw.ustring.sub(str, -999))
end
return string.gsub(text, pattern, '')
end
-- Get the templates from the given wikitext with name=template_name
-- @param text Required. Wikitext to parse.
-- @param flags Range of templates to return, for example 2 or '1,3-5'. Omit to return all templates.
-- @return Sequence of strings containing the wikitext of the requested templates with the specified name
-- @return Original wikitext minus requested templates.
local function getTemplatesByName(text, template_name, flags)
local templates = {}
local flags, blacklist = parseFlags(flags)
local name
local count = 0
for template in string.gmatch(text, '{%b{}}') do
name = mw.text.trim( string.match(template, '{{([^}|\n]+)') or "" ) -- get the template name
if name == template_name then
count = count + 1
if not blacklist and ( not flags or flags[count] or matchFlag(name, flags) )
or blacklist and flags and not flags[count] and not matchFlag(name, flags) then
table.insert(templates, template)
else
text = removeString(text, template)
end
end
end
return templates, text
end
-- Get the position parameter(s) of templates from the given wikitext with name=template_name
local function getTemplateParameterByName(text, template_name, flags)
local templates = {}
local flags, blacklist = parseFlags(flags)
local name
local count = 0
local params, parts, key, value
for template in string.gmatch(text, '{%b{}}') do
name = mw.text.trim( string.match(template, '{{([^}|\n]+)') or "" ) -- get the template name
if name == template_name then
count = count + 1
if not blacklist and ( not flags or flags[count] or matchFlag(name, flags) )
or blacklist and flags and not flags[count] and not matchFlag(name, flags) then
params = string.match(template, '{{[^|}]-|(.*)}}')
local parameters = {}
table.insert(templates, parameters)
local parameter_count = 0
for parameter in mw.text.gsplit(params, '|') do
parts = mw.text.split(parameter, '=')
key = mw.text.trim(parts[1])
if #parts == 1 then
value = key
parameter_count = parameter_count + 1
key = parameter_count
value = string.gsub(string.gsub(value, '@@:@@', '|'), '@@_@@', '=')
parameters[key] = value
end
end
end
end
end
return templates
end
-- Entry points for modules
function p.getTemplatesByName(text, template_name, flags) return getTemplatesByName(text, template_name, flags) end
function p.getTemplateParameterByName(text, template_name, flags) return getTemplateParameterByName(text, template_name, flags) end
return p