Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions Other/Sort title.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
local match = require("Module:String")._match

local p = {}

--[[
Local function which is used to return a number without commas.
For example: 4,722 will become 4722.
--]]
local function cleanNumberFromCommas(title)
return string.gsub(title, "(%d+)(,+)", "%1")
end

--[[
Local function which is used to check if the word is an article.
Returns true if it is, false if it isn't.
--]]
local function isFirstWordAnArticle(word)
word = string.lower(word)
if (word == "a" or word == "an" or word == "the") then
return true
else
return false
end
end

--[[
Local function which is used to return the title without its disambiguation.
--]]
local function getTitleWithoutDisambiguation(title, disambiguation)
local newTitle = string.gsub(title, "%(".. disambiguation .. "%)", "")
return mw.text.trim(newTitle)
end

--[[
Local function which is used to return a title without its first word.
--]]
local function getTitleWithoutFirstWord(title)
return mw.ustring.gsub(title, "^[^%s]*%s*", "")
end

--[[
Local function which is used to return the first word from a title.
--]]
local function getFirstWord(title)
return match(title, "^[^%s]*", 1, 1, false, "")
end

--[[
Local function which is used to return a sort key for a specific part.
--]]
local function getSortKey(title, firstWord)
local sortKey = title
if (isFirstWordAnArticle(firstWord) and firstWord ~= title) then
title = getTitleWithoutFirstWord(title)
sortKey = title .. ", " .. firstWord
end

return sortKey
end

--[[
Local function which is used to return the disambiguation sort key.
--]]
local function getDisambiguationSortKey(disambiguation)
if (disambiguation == "") then
return ""
end

local firstWord = getFirstWord(disambiguation)
local disambiguationSortKey = getSortKey(disambiguation, firstWord)
return "(" .. disambiguationSortKey .. ")"
end

--[[
Local function which is used to return the disambiguation from a title.
--]]
local function getDisambiguation(title)
local disambiguation = match(title, "%s%((.-)%)", 1, -1, false, "")
if (disambiguation == "") then
return ""
else
return disambiguation
end
end

--[[
The main function.
--]]
local function _main(title)
if (not title) then
title = mw.title.getCurrentTitle().text
end

local firstWord = getFirstWord(title)
local disambiguation = getDisambiguation(title)
local disambiguationSortKey = getDisambiguationSortKey(disambiguation)

title = getTitleWithoutDisambiguation(title, disambiguation)
title = cleanNumberFromCommas(title)
title = getSortKey(title, firstWord)

local sortKey = title .. " " .. disambiguationSortKey
return mw.text.trim(sortKey)
end

--[[
Public function which allows modules to retrieve a sort key.
--]]
function p._getSortKey()
return _main(nil)
end

--[[
Public function which allows templates to retrieve a sort key.
--]]
function p.getSortKey(frame)
return _main(nil)
end

--[[
Public function which allows templates to retrieve the sort key inside a DEFAULTSORT.
--]]
function p.getDefaultSort(frame)
local sortKey = _main(nil)
return frame:preprocess{text = "{{DEFAULTSORT:" .. sortKey .. "}}"}
end

--[[
Public function which is used for testing various names and not the current page name.
--]]
function p.testcases(frame)
local getArgs = require('Module:Arguments').getArgs
local args = getArgs(frame)
return _main(args[1])
end

return p
88 changes: 88 additions & 0 deletions Other/SortName.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
local p = {}

function p.sortname(frame)
local currentpage = mw.title.getCurrentTitle()
local pagetitle = frame.args[1] or currentpage.text
local langvar = mw.language.getContentLanguage()
local text1 = ''
local text2 = ''
local parts = { 'de','De','von','Von','du','Du','del','Del','zu','Zu','di','Di','van','Van','na','Na','le','Le','de\'','De\'' }
local partmatch = false
if string.find( pagetitle, ' ' ) ~= nil then
pagetitle = string.gsub( string.gsub( string.gsub( pagetitle, '%b()', '' ), ' +', ' '), ' $', '' )
if string.find( pagetitle, '^List of ' ) ~= nil then
pagetitle = langvar:ucfirst( string.gsub( pagetitle, '^List of ', '', 1 ) )
elseif string.find( pagetitle, '^The ' ) ~= nil then
pagetitle = string.gsub( pagetitle, '^The ', '' ) .. ', The'
else
pagetitle = string.gsub( pagetitle, ',.*$', '' )
pagetitle = string.gsub( pagetitle, ' of .*$', '' )
for i in ipairs( parts ) do
if string.find( pagetitle, ' ' .. parts[i] .. ' ' ) ~= nil then
text1 = string.sub( pagetitle, string.find( pagetitle, ' ' .. parts[i] .. ' ' ) + 1, #pagetitle )
text2 = string.sub( pagetitle, 0, string.find( pagetitle, ' ' .. parts[i] .. ' ' ) - 1 )
pagetitle = text1 .. ', ' .. text2
partmatch = true
break
end
end
if not partmatch and string.find( pagetitle, ' ' ) ~= nil then
text1 = string.sub( pagetitle, string.find( pagetitle, ' [^ ]*$' ) + 1, #pagetitle )
text2 = string.sub( pagetitle, 0, string.find( pagetitle, ' [^ ]*$' ) - 1 )
local romannumeral = roman_to_numeral(text1)
if romannumeral == -1 then
pagetitle = text1 .. ', ' .. text2
else
if string.find( text2, ' ' ) == nil then
pagetitle = text2 .. ' ' .. romannumeral
else
text1 = string.sub( text2, string.find( text2, ' [^ ]*$' ) + 1, #text2 )
text2 = string.sub( text2, 0, string.find( text2, ' [^ ]*$' ) - 1 )
pagetitle = text1 .. ' ' .. romannumeral .. ', ' .. text2
end
end
end
end
end
return pagetitle
end

-- the following table and roman_to_numeral function came from Module:ConvertNumeric, created by User:Dcoetzee
roman_numerals = {
I = 1,
V = 5,
X = 10,
L = 50,
C = 100,
D = 500,
M = 1000
}

-- Converts a given valid roman numeral (and some invalid roman numerals) to a number. Returns -1, errorstring on error
function roman_to_numeral(roman)
if type(roman) ~= "string" then return -1, "roman numeral not a string" end
local rev = roman:reverse()
local raising = true
local last = 0
local result = 0
for i = 1, #rev do
local c = rev:sub(i, i)
local next = roman_numerals[c]
if next == nil then return -1, "roman numeral contains illegal character " .. c end
if next > last then
result = result + next
raising = true
elseif next < last then
result = result - next
raising = false
elseif raising then
result = result + next
else
result = result - next
end
last = next
end
return result
end

return p
143 changes: 143 additions & 0 deletions Testcases/Sort title.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
-- Unit tests for [[Module:Sort title]]. Click talk page to run tests.
local p = require('Module:UnitTests')

function p:test_1_1_titles_live()
self:preprocess_equals_many('{{#invoke:Sort title|testcases|', '}}', {
{'Lost', "Lost"},
{'Lost (TV series)', "Lost (TV series)"},
{'Lost (2004 TV series)', "Lost (2004 TV series)"},
{'Lost (American TV series)', "Lost (American TV series)"},
{'The Flash', "Flash, The"},
{'The Flash (TV series)', "Flash, The (TV series)"},
{'Pilot (The Flash)', "Pilot (Flash, The)"},
{'The Trap (The Flash)', "Trap, The (Flash, The)"},
{'4,722 Hours', "4722 Hours"},
{'4,722 Hours (Agents of S.H.I.E.L.D.)', "4722 Hours (Agents of S.H.I.E.L.D.)"},
})
end

function p:test_1_2_titles_sandbox()
self:preprocess_equals_many('{{#invoke:Sort title/sandbox|testcases|', '}}', {
{'Lost', "Lost"},
{'Lost (TV series)', "Lost (TV series)"},
{'Lost (2004 TV series)', "Lost (2004 TV series)"},
{'Lost (American TV series)', "Lost (American TV series)"},
{'The Flash', "Flash, The"},
{'The Flash (TV series)', "Flash, The (TV series)"},
{'Pilot (The Flash)', "Pilot (Flash, The)"},
{'The Trap (The Flash)', "Trap, The (Flash, The)"},
{'4,722 Hours', "4722 Hours"},
{'4,722 Hours (Agents of S.H.I.E.L.D.)', "4722 Hours (Agents of S.H.I.E.L.D.)"},
})
end

function p:test_2_1_special_characters_live()
self:preprocess_equals_many('{{#invoke:Sort title|testcases|', '}}', {
{'A', "A"},
{'An', "An"},
{'The', "The"},
{'A (Dab)', "A (Dab)"},
{'A (A)', "A (A)"},
{'A Title', "Title, A"},
{'A Title (Dab)', "Title, A (Dab)"},
{'A Title (A Dab)', "Title, A (Dab, A)"},
{'Title (Dab)', "Title (Dab)"},
{'Title (A Dab)', "Title (Dab, A)"},
{'The Title', "Title, The"},
{'An Egg', "Egg, An"},
{'A. B. and C.', "A. B. and C."},
{'\'A\' Title', "\'A\' Title"},
{'A, My Name', "A, My Name"},
{'...Title', "...Title"},
{'...A Title', "...A Title"},
{'4,722 Hours', "4722 Hours"}
})
end

function p:test_2_2_special_characters_sandbox()
self:preprocess_equals_many('{{#invoke:Sort title/sandbox|testcases|', '}}', {
{'A', "A"},
{'An', "An"},
{'The', "The"},
{'A (Dab)', "A (Dab)"},
{'A (A)', "A (A)"},
{'A Title', "Title, A"},
{'A Title (Dab)', "Title, A (Dab)"},
{'A Title (A Dab)', "Title, A (Dab, A)"},
{'Title (Dab)', "Title (Dab)"},
{'Title (A Dab)', "Title (Dab, A)"},
{'The Title', "Title, The"},
{'An Egg', "Egg, An"},
{'A. B. and C.', "A. B. and C."},
{'\'A\' Title', "\'A\' Title"},
{'A, My Name', "A, My Name"},
{'...Title', "...Title"},
{'...A Title', "...A Title"},
{'4,722 Hours', "4722 Hours"}
})
end

--[[
function p:test_3_1_roman_live()
self:preprocess_equals_many('{{#invoke:Sort title|testcases|', '}}', {
{'Treehouse of Horror', "Treehouse of Horror"},
{'Treehouse of Horror 6', "Treehouse of Horror 6"},
{'The Treehouse of Horror VI', "Treehouse of Horror 6, The"},
{'Words with abbreviation I.V.Not.roman.', "Words with abbreviation I.V.Not.roman."},
{'Words with abbreviation S.H.I.E.L', "Words with abbreviation S.H.I.E.L"},
{'Treehouse of Horror I', "Treehouse of Horror 1"},
{'Treehouse of Horror II', "Treehouse of Horror 2"},
{'Treehouse of Horror III', "Treehouse of Horror 3"},
{'Treehouse of Horror IV', "Treehouse of Horror 4"},
{'Treehouse of Horror V', "Treehouse of Horror 5"},
{'Treehouse of Horror VI', "Treehouse of Horror 6"},
{'Treehouse of Horror VII', "Treehouse of Horror 7"},
{'Treehouse of Horror VIII', "Treehouse of Horror 8"},
{'Treehouse of Horror IX', "Treehouse of Horror 9"},
{'Treehouse of Horror X', "Treehouse of Horror 10"},
{'Treehouse of Horror XI', "Treehouse of Horror 11"},
{'Treehouse of Horror XII', "Treehouse of Horror 12"},
{'Treehouse of Horror XIII', "Treehouse of Horror 13"},
{'Treehouse of Horror XIV', "Treehouse of Horror 14"},
{'Treehouse of Horror XV', "Treehouse of Horror 15"},
{'Treehouse of Horror XVI', "Treehouse of Horror 16"},
{'Treehouse of Horror XVII', "Treehouse of Horror 17"},
{'Treehouse of Horror XVIII', "Treehouse of Horror 18"},
{'Treehouse of Horror XIX', "Treehouse of Horror 19"},
{'Treehouse of Horror XX', "Treehouse of Horror 20"}
})
end--]]

function p:test_3_2_roman_sandbox()
self:preprocess_equals_many('{{#invoke:Sort title/sandbox|testcases|', '}}', {
{'Treehouse of Horror', "Treehouse of Horror"},
{'Treehouse of Horror 6', "Treehouse of Horror 6"},
{'The Treehouse of Horror VI', "Treehouse of Horror 6, The"},
{'Words with abbreviation I.V.Not.roman.', "Words with abbreviation I.V.Not.roman."},
{'Words with abbreviation S.H.I.E.L', "Words with abbreviation S.H.I.E.L"},
{'Treehouse of Horror I', "Treehouse of Horror 1"},
{'Treehouse of Horror II', "Treehouse of Horror 2"},
{'Treehouse of Horror III', "Treehouse of Horror 3"},
{'Treehouse of Horror IV', "Treehouse of Horror 4"},
{'Treehouse of Horror V', "Treehouse of Horror 5"},
{'Treehouse of Horror VI', "Treehouse of Horror 6"},
{'Treehouse of Horror VII', "Treehouse of Horror 7"},
{'Treehouse of Horror VIII', "Treehouse of Horror 8"},
{'Treehouse of Horror IX', "Treehouse of Horror 9"},
{'Treehouse of Horror X', "Treehouse of Horror 10"},
{'Treehouse of Horror XI', "Treehouse of Horror 11"},
{'Treehouse of Horror XII', "Treehouse of Horror 12"},
{'Treehouse of Horror XIII', "Treehouse of Horror 13"},
{'Treehouse of Horror XIV', "Treehouse of Horror 14"},
{'Treehouse of Horror XV', "Treehouse of Horror 15"},
{'Treehouse of Horror XVI', "Treehouse of Horror 16"},
{'Treehouse of Horror XVII', "Treehouse of Horror 17"},
{'Treehouse of Horror XVIII', "Treehouse of Horror 18"},
{'Treehouse of Horror XIX', "Treehouse of Horror 19"},
{'Treehouse of Horror XX', "Treehouse of Horror 20"},
{'7:15 A.M.', "7:15 A.M."},
{'The House of L', "House of L, The"},
})
end

return p
20 changes: 20 additions & 0 deletions Testcases/SortName.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
local p = require('Module:UnitTests')

function p:test_sortname()
self:preprocess_equals_many('{{#invoke:SortName|sortname|', '}}', {
{ 'Jim Excelsior Tyler', 'Tyler, Jim Excelsior' },
{ 'Jim', 'Jim' },
{ 'List of people named Jim', 'People named Jim' },
{ 'List of jims', 'Jims' },
{ 'Jim Tyler (musician)', 'Tyler, Jim' },
{ 'Jim Tyler, man and myth', 'Tyler, Jim' },
{ 'Jim Tyler of Clan Tyler', 'Tyler, Jim' },
{ 'Jim von Tyler', 'von Tyler, Jim' },
{ 'Jim Von Tyler', 'Von Tyler, Jim' },
{ 'Jim Tyler III', 'Tyler 3, Jim' },
{ 'Jim III', 'Jim 3' },
{ 'Jim Tyler III, Emperor of New Brunswick', 'Tyler 3, Jim' }
})
end

return p
Loading