Module:Sandbox/維基搗蛋鬼/talkpage
跳到导航
跳到搜索
zhwp:模块:沙盒/逆襲的天邪鬼/talkpage/doc
本页面为软重定向。
--[[ 無腦地從[:zhwp:Module:沙盒/逆襲的天邪鬼/talkpage]粘了過來。都是我寫的,別講究了…… ]]-- local f = {} f.DATEPATTERN = '(%d-)年(%d-)月(%d-)日 %([一二三四五六日]-%) (%d-):(%d-) %(CST%)' f.USERPREFIX = { 'user:', '用戶:', '用户:', '使用者:', 'user talk:', 'user_talk:', '用戶討論:', '用户讨论:', '使用者討論:', 'special:用户贡献/', 'special:contributions/', 'special:用戶貢獻/', 'special:使用者貢獻/', '特殊:用户贡献/', '特殊:用戶貢獻/', '特殊:使用者貢獻/', '特殊:contributions/' } f.MINDATE = '1970年1月1日 (六) 13:00 (CST)' f.MAXDATE = '9999年12月31日 (六) 23:59 (CST)' --- 反序尋找字符串 local function rfind(s, pattern, init) local x, y local i = init or #s local len = #s x, y = string.find(string.reverse(s), string.reverse(pattern), len-i+1, true) if x then return len-y+1, len-x+1 end end --- 生成用戶名鏈接。默認是指向用戶頁(IP用戶為貢獻頁)的鏈接。 -- @param name 用戶名 -- @param style 自定義樣式,其中$USER會被換成用戶名。 -- @param ipstyle IP用戶的自定義樣式。若未指定則與style相同。 -- @return 維基格式的用戶名鏈接 local function getuserlink(name, style, ipstyle) if string.find(name, '^%d-%.%d-%.%d-%.%d-$') then return string.gsub(ipstyle or style or '[[Special:用户贡献/$USER|$USER]]', '$USER', name) else return string.gsub(style or '[[User:$USER|$USER]]', '$USER', name) end end --- TODO 去除掉影響分析的文字,例如「===」、「<pre>」等 -- @param orintext 原始討論串。 -- @return 經過預處理之後的討論串。去掉一些搗亂的內容。 local function preprocess(orintext, titlelevel) local text = orintext text = string.gsub(text, titlelevel .. '=', '---') text = string.gsub(text, '<pre>.-</pre>', '') text = string.gsub(text, '<nowiki>.-</nowiki>', '') text = string.gsub(text, '{{移動至|.-}}', '') text = string.gsub(text, '{{talkback|.-}}', '') text = string.gsub(text, '{{deltalk|.-}}', '') text = string.gsub(text, '{{移动自|.-}}', '') return text end --- 從長長的討論串中找到特定主題。如果未指定主題則將所有主題分割開並存入table中。 -- @param orintext 原始討論串。 -- @param topic 待提取的主題。未指定的話則改為分割所有主題。 -- @param ispattern 表示topic是否為lua的匹配字符串。 -- @return 返回一個鍵為討論標題值為討論內容的table。如果沒有則返回nil。 local function extracttopic(args) local orintext = args.text local topic = args.topic local ispattern = args.ispattern local titlelevel = args.titlelevel=='3' and '===' or '==' -- 預處理 local text = titlelevel .. '\n\n' .. preprocess(orintext, titlelevel) .. '\n' .. titlelevel local result = {} local found = nil local topic2 = topic and mw.text.trim(topic) for title, content in string.gmatch(text, '[ ]*(.-)[ ]*'..titlelevel..'[ ]*\n(.-)\n'..titlelevel) do local ok = false if topic2 and (not ispattern) and title == topic2 then ok = true elseif topic2 and ispattern and (string.match(title, topic2)) then ok = true elseif not topic2 then ok = true end if ok then found = true local temptitle = title local i = 1 while result[temptitle] do i = i + 1 temptitle = title .. ' (' .. i .. ')' end result[temptitle] = content end end return found and result end --- 將討論串上的日期轉為一個數字。 -- @param date 討論串格式的日期。 -- @return 將數字直接拼起來。不是時間戳。 local function date2num(date) local y,m,d,h,min = string.gmatch(date, f.DATEPATTERN)() if y and m and d and h and min then return y*100000000+m*1000000+d*10000+h*100+min else return 0 end end --- 比較兩個日期的大小。 -- @param date1 -- @param date2 -- @return 若date1<date2則返回true。 local function comparedate(date1, date2) return date2num(date1) < date2num(date2) end --- 統計討論串中各個簽名的次數和最後發言時間。 -- @param orintext 原始討論串 -- @return @todo TODO 需要重寫 function f._count(orintext) -- 預處理 local text = '\n' .. orintext local lowertext = string.lower(text) -- 尋找日期 local result = {} local x, y y = 1 repeat x, y = text.find(text, f.DATEPATTERN, y+1) if not x then break end local date = string.sub(text, x, y) -- 截取當前行以便於尋找用戶名 local t1, t2 = rfind(text, '\n', x) local curtalk = string.sub(lowertext, t1, x-1) -- 尋找用戶名 local name = nil for i, v in ipairs(f.USERPREFIX) do local t3, t4 = rfind(curtalk, '[[' .. v) if t4 then local t5 = (string.find(curtalk, '[/#|%]]', t4)) if t5 then -- 確定用戶名 name = string.sub(text, t1+t4, t1+t5-2) -- 首字母大寫 local firstletter = string.byte(name, 1, 1) if firstletter >= 97 and firstletter <=122 then name = string.upper(string.sub(name, 1, 1)) .. string.sub(name, 2, -1) end break end end end name = name or 'Example' if not result[name] then result[name] = {count = 1, firstdate = date, lastdate = date} else result[name].count = result[name].count + 1 if comparedate(result[name].lastdate, date) then result[name].lastdate = date end if comparedate(date, result[name].firstdate) then result[name].firstdate = date end end until false return result end local function maketable(counttable, args) local tabletype = args.tabletype and mw.text.trim(args.tabletype) or 'user' local top = '{| class="wikitable sortable"\n|-' local header if tabletype == 'all' then top = '{| class="wikitable"\n|-' end local result = { top } if tabletype == 'topic' then table.insert(result, '! 主題 !! 發言次數 !! 參與者人數 !! 發起人 !! 最後發言者 !! 最後發言時間') for k, v in pairs(counttable.topics) do if v.count > 0 then table.insert(result, string.format('|-\n| %s || %s || %s || %s || %s || %s', k, v.count, v.usercount, getuserlink(v.firstname, args.userlink, args.ipuserlink), getuserlink(v.lastname, args.userlink, args.ipuserlink), v.lastdate)) end end elseif tabletype == 'topicsimple' then table.insert(result, '! 主題 !! 發言次數 !! 最後發言者 !! 最後發言時間') for k, v in pairs(counttable.topics) do if v.count > 0 then table.insert(result, string.format('|-\n| %s || %s || %s || %s', k, v.count, getuserlink(v.lastname, args.userlink, args.ipuserlink), v.lastdate)) end end elseif tabletype == 'all' then table.insert(result, '! 主題 !! 用戶 !! 發言次數 !! 最後發言時間') for k, v in pairs(counttable.topics) do if v.count > 0 then local first = k .. ' || ' if v.usercount > 1 then first = 'rowspan=' .. v.usercount .. ' | ' .. first end for k2, v2 in pairs(v.users) do table.insert(result, string.format('|-\n| %s%s || %s || %s', first, getuserlink(k2, args.userlink, args.ipuserlink), v2.count, v2.lastdate)) first = '' end end end else table.insert(result, '! 用戶 !! 發言次數 !! 最後發言時間') for k, v in pairs(counttable.users) do table.insert(result, string.format('|-\n| %s || %s || %s', getuserlink(k, args.userlink, args.ipuserlink), v.count, v.lastdate)) end end table.insert(result, '|}') return table.concat(result, '\n') end --- 對簽名數據進行匯總 -- @param stat 通過count函數得到的統計數據 -- @return 一個table,發言數、發言人數、最後發言者、最後發言時間 local function getstat(data) local count = 0 local usercount = 0 local lastdate = f.MINDATE local lastname = nil local firstdate = f.MAXDATE local firstname = nil for username, userinfo in pairs(data) do count = count + userinfo.count usercount = usercount + 1 if comparedate(lastdate, userinfo.lastdate) then lastdate = userinfo.lastdate lastname = username end if comparedate(userinfo.firstdate, firstdate) then firstdate = userinfo.firstdate firstname = username end end return { count = count, usercount = usercount, firstdate = firstdate, firstname = firstname, lastdate = lastdate, lastname = lastname } end --- 統計討論串中各個簽名的次數和最後發言時間。 -- @param args -- @return local function getcount(args) local talk = string.gsub(args.text, '\r', '\n') local userdata = {} local result = { users = userdata, topics = {} } local topics = extracttopic(args) or {} for title, content in pairs(topics) do local topicdata = f._count(content) for username, userinfo in pairs(topicdata) do local dat = userdata[username] or { count = 0, lastdate = f.MINDATE } dat.count = dat.count + userinfo.count dat.lastdate = comparedate(dat.lastdate, userinfo.lastdate) and userinfo.lastdate or dat.lastdate userdata[username] = dat end result.topics[title] = getstat(topicdata) result.topics[title].users = topicdata end return result end --- 獲取最後簽名。 -- @param args -- @return 一個table,包含用戶名和日期。 local function getlastsign(args) local r = getcount(args) local lastname = nil local lastdate = f.MINDATE for k, v in pairs(r.users) do if comparedate(lastdate, v.lastdate) then lastname = k lastdate = v.lastdate end end return {name=lastname, date=lastdate} end --- 將維基百科模板上的參數轉為lua的table。 -- @param frame 維基百科模板上的參數。 -- @return 一個table,包括各個參數。 local function getargs(frame) return { text = mw.title.new(frame.args[1]):getContent(), topic = frame.args.topic, ispattern = frame.args.ispattern, userlink = frame.args.userlink, ipuserlink = frame.args.ipuserlink, tabletype = frame.args.type, titlelevel = frame.args.titlelevel } end --- 統計討論頁發言情況。詳情見文檔頁。 -- @param frame 維基百科頁面名。 -- @return 一張表格。 function f.analyse(frame) local args = getargs(frame) return maketable(getcount(args), args) end --- 獲取最後一個發言的用戶。 -- @param frame 維基百科頁面名。 -- @return 一個用戶名,不使用鏈接。 function f.lastname(frame) return getlastsign(getargs(frame)).name end --- 獲取最後一個發言的日期。 -- @param frame 維基百科頁面名。 -- @return 一個日期。 function f.lastdate(frame) return getlastsign(getargs(frame)).date end --- 獲取最後一個簽名。 -- @param frame 維基百科頁面名。 -- @return 一個簽名鏈接附上一個日期。 function f.lastsign(frame) local args = getargs(frame) local lastsign = getlastsign(args) if lastsign.name then return string.format('%s %s', getuserlink(lastsign.name, args.userlink, args.ipuserlink), lastsign.date) end end --- 統計簽名數量。 -- @param frame 維基百科頁面名。 -- @return 一個數字。 function f.count(frame) local data = getcount(getargs(frame)) local username = frame.args.user and mw.text.trim(frame.args.user) if not username then local num = 0 for k, v in pairs(data.topics) do num = num + v.count end return num elseif data.users[username] then return data.users[username].count else return 0 end end --- 統計簽名者數量。 -- @param frame 維基百科頁面名。 -- @return 一個數字。 function f.countuser(frame) local data = getcount(getargs(frame)).users local count = 0 for _ in pairs(data) do count = count + 1 end return count end -- 以下用於本地測試 --[[ f.countsigns = getcount f.lastsign = getlastsign f.maketable = maketable ]] return f