-- Counts wiki links within a wiki article. Supports returning total number of links, blue, red, or a list of red, blue, total, along with blue to red percentage
-- Gts-tg@el wiki, Sep. 2017
local p = {}
-- turn line to list
-- params: line (string), delimiter (string)
-- return list
local function explode(line, delimiter, specialCharacters)
local links = {}
local chars = {
[":"]=true,
["."]=true,
["«"]=true,
["{"]=true,
["<"]=true,
["#"]=true
}
local ignore = false
local regex = '[^' .. delimiter .. ']+'
for link in string.gmatch(line, regex) do -- get all content within [ ]
for schar,value in pairs(chars) do -- clean up non links
if (schar == specialCharacters) == false and -- need to regex for multiple characters
string.match(link, "%" .. schar) ~= nil
then
ignore = true
break
end
end
if ignore == false then
link = mw.ustring.gsub(link, '[%[%]]', '') -- remove [[ ]], will be added later if requested
links[#links+1] = link
end
end
return links
end
-- merge lists
-- params: l1 (list), l2 (list)
-- return list
local function listJoin(l1, l2)
for i=1,#l2 do
l1[#l1+1] = l2[i]
end
return l1
end
-- get wikilinks from text
-- params: text (string)
-- return list
local function getLinks(text, specialCharacters)
local links = ''
local result = {}
local cleaned = nil
for line in string.gmatch(text,'[^\r\n]+') do
links = string.match(line, "%[%[.*%]%]") -- cleanup line from anything not in [[ ]]
if links ~= nil then
links = mw.ustring.gsub(links, '%]%].-%[%[', ']]~[[') -- remove non link text, ~ is used as delimiter for lines where more than one link exists
links = mw.ustring.gsub(links, '%|.-%]%]', ']]') -- remove custom title i.e. [[title|custom title]]
result = listJoin(result, explode(links, '~', specialCharacters))
end
end
return result
end
-- count links
-- params: articleTitle (string), linkType (string), showLinks (int)
-- return string
local function counter(articleTitle, linkType, showLinks, specialCharacters)
if articleTitle == '' then return -1 end
local article = mw.title.new(articleTitle)
local content = article:getContent()
if content == nil then return -1 end
local links = getLinks(content, specialCharacters)
local str = ''
if linkType ~= 'total' or showLinks == 1 then
local blue = 0
for i=1, #links do
-- using mw.wikibase.getEntityIdForTitle(links[i]) (wikidata entry existing) first as it's much faster and saves a few hundred calls
-- using getContent as a fallback to see if article exists, do not use id or exists method as they query the DB and are counted as ''expensive'' and fail after a few hundreds
if mw.wikibase.getEntityIdForTitle(links[i]) or
mw.title.new(links[i],0):getContent() then
blue = blue + 1
if linkType == 'red' then
links[i] = ''
end
else
if linkType == 'blue' then
links[i] = ''
end
end
end
local red = #links - blue
if linkType == 'red' then
str = red
elseif linkType == 'blue' then
str = blue
elseif linkType == 'percentage' then
str = tostring(math.floor((#links-red)/#links * 100))
end
if showLinks == 1 then
str = 'Σύνολο: ' .. #links .. ', Μπλέ: ' .. blue .. ', Κόκκινοι: ' .. tostring(red) .. '\n' .. '*[[' .. table.concat(links,']]\n*[[') .. ']]'
str = string.gsub(str, '%*%[%[%]%]\n', '')
end
else
str = #links
end
return str
end
-- main
-- params: frame (object)
-- return string
function p.count(frame)
local result = ''
local articleTitle = frame.args['article'] or ''
local linkType = frame.args['type']
local showLinks = tonumber(frame.args['showlinks']) or 0
local specialCharacters = frame.args['characters'] or nil
-- i18n
local linkTypes = {
['κόκκινοι'] = 'red',
['μπλε'] = 'blue',
['σύνολο'] = 'total',
['ποσοστό'] = 'percentage',
}
linkType = linkTypes[linkType]
if linkType == nil then showLinks = 1 end
result = counter(articleTitle, linkType, showLinks, specialCharacters)
if result == -1 then result = 'Δεν βρέθηκε σελίδα με τίτλο ' .. articleTitle end
return result
end
return p
-- =p.count{args={['article'] = ''}}