Toggle menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:ParseList

From bg3.wiki
Revision as of 22:11, 24 July 2023 by Rayo (talk | contribs) (Add drow and dragonborn subraces)

Doc page: Module:ParseList/doc

This module allows you to process a list of values (separated by a comma by default) and display them in a variety of useful formats.

{{#invoke:ParseList|main|Fighter, Cleric, Wizard}}

Becomes:

Fighter, Cleric, and Wizard

Parameters

The first parameter is the list to be processed. The remaining parameters are optional:

parameter default meaning
style 'text' The desired output format, see below for possibilities.
type Deprecated synonym for style.
delimiter ',' The character that should serve as a delimiter of the input list. This can actually be a string of multiple characters which will all work as a delimiter, but that usage is discouraged as it may cause confusion.
makePlural (empty) If provided and not blank, means that each element will be turned into a plural word.
makeSingular (empty) If provided and not blank, means that each element will be turned into singular.
makeLowercase (empty) If provided and not blank, means that each element will be made all-lowercase.
makeLinks (empty)

If provided and not blank, means that each element will be made into a link.

If any transforms like plural, singular, or lowercase were specified, the original element will be the link destination, and the transformed version the link text. E.g., the list element "Apple" would become [[Apple|apples]] if makePlural, makeLowercase, and makeLinks were provided.

useTemplate (empty)

If provided, will use the provided template on each element, i.e., turn every X into {{Template|X}}.

This is done after any transforms like plural, singular and lowercase. E.g., the list element "Apple" would become {{Template|apples}} if makePlural, makeLowercase, and useTemplate were provided.

useTemplate2 (empty)

If provided, will use the provided template on each element and its transformed form as two template arguments.

E.g., the list element "Apple" would become {{Template|Apple|apples}} if makePlural, makeLowercase, and useTemplate were provided.

textDelim ', '

If style is text, this is used as the delimiter for the output list.

Setting this causes the default value for textLastDelim to be changed to the same value, since the default value of textLastDelim is unlikely to be useful with anything other than the default value of textDelim.

Note that the default value is not just a comma; it's a comma followed by a space character.

textLastDelim (conditional)

If style is text, this is used as the delimiter between the last two elements of the output list.

If textDelim is not set (i.e., left at its default value), then the default value for this is ', and ' such that an input list "X, Y, Z" would be turned into "X, Y, and Z". You could leave textDelim unset, but set textLastDelim = <nowiki>, or </nowiki> to get the output "X, Y, or Z" instead.

If textDelim is set, then this defaults to the same value as that. E.g., specifying textDelim = <nowiki> + </nowiki> would transform the input list "X, Y, Z" into "X + Y + Z" without needing to also change the value of textLastDelim.

Note: The use of <nowiki> here is to prevent leading and trailing space characters from being ignored when setting textDelim or textLastDelim to a string that should start and/or end with a space character.

The automatic plural/singular transforms are able to recognize certain irregular plurals and handle them correctly, such as "thieves" and "quarterstaves." This is handled partly through a table of explicit special conversions like staff -> staves, and partly through logical rules like ...f --> ...ves. If you find a word that produces a wrong result, it should be added to the table of explicit conversions.

The makeLink, useTemplate, and useTemplate2 arguments are mutually exclusive; when several are provided, only the first will take effect.

Output styles

The value of the style parameter can be the following:

value example output
text Fighter, Cleric, and Wizard
simpleList Fighter, Cleric, and Wizard
htmlList Fighter, Cleric, and Wizard
htmlListNoBullets Fighter, Cleric, and Wizard
htmlListNoBulletsOrMargin Fighter, Cleric, and Wizard
tableList Fighter, Cleric, and Wizard
none Fighter, Cleric, and Wizard

The style none is useful if each element is being transformed into an HTML element such that no textual delimiters are desired.

Examples

Make Links

{{#invoke: ParseList | main | Fighter, Cleric, Wizard | makeLinks = yes }}

Result:

Fighter, Cleric, and Wizard

Make plural

{{#invoke: ParseList | main | Fighter, Cleric, Wizard | makePlural = yes }}

Result:

Fighters, Clerics, and Wizards

Make Plural Links

{{#invoke: ParseList | main | Fighter, Cleric, Wizard | makeLinks = yes | makePlural = yes }}

Result:

Fighters, Clerics, and Wizards

Make Plural Links, end with "or"

{{#invoke: ParseList | main | Fighter, Cleric, Wizard | makeLinks = yes | makePlural = yes | textLastDelim = <nowiki>, or </nowiki> }}

Result:

Fighters, Clerics, and Wizards

Make Plural Links, turn into HTML list

{{#invoke: ParseList | main | Fighter, Cleric, Wizard | makeLinks = yes | makePlural = yes | style = htmlList }}

Result:

Fighters, Clerics, and Wizards


local getArgs = require('Module:Arguments').getArgs
local p = {}

-- Config options, set in main function
local listDelimiters
local makeElementsLinks
local makeElementsPlural
local makeElementsSingular
local finalJoiningWord

local function splitListString(listString)
    local strings = {}
    for str in listString:gmatch("[^" .. listDelimiters .. "]+") do
        table.insert(strings, str:match("^%s*(.-)%s*$"))
    end
    return strings
end

-- We don't need to cover most regular English words, as they're very unlikely
-- to ever be used with this module.  The kind of stuff you want to add here is
-- gameplay elements like classes, weapons, races, etc. that you may want to
-- pluralize in a listing.
local specialPlurals = {
	-- Weapons
	Quarterstaff = "Quarterstaves",
	quarterstaff = "quarterstaves",
	Staff = "Staves",
	staff = "staves",
	-- Races
	Gith = "Gith",
	gith = "gith",
	Githyanki = "Githyanki",
	githyanki = "githyanki",
	Duergar = "Duergar",
	duergar = "duergar",
	Drow = "Drow",
	drow = "drow",
	["Lolth-Sworn Drow"] = "Lolth-Sworn Drow",
	["Lolth-sworn drow"] = "Lolth-sworn drow",
	["Seldarine Drow"] = "Seldarine Drow",
	["Seldarine drow"] = "Seldarine drow",
	Dragonborn = "Dragonborn",
	dragonborn = "dragonborn",
	["Black Dragonborn"] = "Black Dragonborn",
	["black dragonborn"] = "black dragonborn",
	["Blue Dragonborn"] = "Blue Dragonborn",
	["blue dragonborn"] = "blue dragonborn",
	["Brass Dragonborn"] = "Brass Dragonborn",
	["brass dragonborn"] = "brass dragonborn",
	["Bronze Dragonborn"] = "Bronze Dragonborn",
	["bronze dragonborn"] = "bronze dragonborn",
	["Copper Dragonborn"] = "Copper Dragonborn",
	["copper dragonborn"] = "copper dragonborn",
	["Gold Dragonborn"] = "Gold Dragonborn",
	["gold dragonborn"] = "gold dragonborn",
	["Green Dragonborn"] = "Green Dragonborn",
	["green dragonborn"] = "green dragonborn",
	["Red Dragonborn"] = "Red Dragonborn",
	["red dragonborn"] = "red dragonborn",
	["Silver Dragonborn"] = "Silver Dragonborn",
	["silver dragonborn"] = "silver dragonborn",
	["White Dragonborn"] = "White Dragonborn",
	["white dragonborn"] = "white dragonborn",
	-- Creature types
	Fey = "Fey",
	fey = "fey",
	Undead = "Undead",
	undead = "undead",
}

local function makePlural(str)
	local sp = specialPlurals[str]
	if sp then
		return sp
	end
	local lastLetter = str:sub(-1)
	if lastLetter == "y" then
		return str:sub(1, -2) .. "ies"
	elseif lastLetter == "f" then
		return str:sub(1, -2) .. "ves"
	end
	return str .. "s"
end

local function makeSingular(str)
	local special
	for k, v in pairs(specialPlurals) do
		if v == str then
			special = k
			break
		end
	end
	if special then
		return special
	end
	if str:sub(-3) == "ies" then
		return str:sub(1, -4) .. "y"
	end
	return str:sub(1, -2)
end

local function processElement(str)
	local modified = str
	if makeElementsPlural then
		modified = makePlural(str)
	elseif makeElementsSingular then
		modified = makeSingular(str)
	end
	if makeElementsLinks then
		return "[[" .. str .. "|" .. modified .. "]]"
	else
		return modified
	end
end

local converters = {
	sentence = function (elements)
	    local count = #elements
	    if count == 0 then
	    	return ""
	    elseif count == 1 then
	    	return elements[1]
	    elseif count == 2 then
			return elements[1] .. " " .. finalJoiningWord .. " " .. elements[2]
	    end
	    local result = ""
		for i, str in ipairs(elements) do
			if i < count then
				result = result .. str .. ", "
			else
				result = result .. finalJoiningWord .. " " .. str
			end
	    end
	    return result
	end,
	htmlList = function (elements)
		local result = ""
		for i, str in ipairs(elements) do
			result = result .. "* " .. str .. "\n"
		end
		return result
	end,
	simpleList = function (elements)
		local result = ""
		local first = true
		for i, str in ipairs(elements) do
			if first then
				result = str
				first = false
			else
				result = result .. ", " .. str
			end
		end
		return result
	end,
}

function p.main(frame)
	local args = getArgs(frame, { frameOnly = true })
	return p._main(args)
end

function p._main(args)
	listDelimiters = args['delimiter'] or ","
	makeElementsLinks = args['makeLinks']
	makeElementsPlural = args['makePlural']
	makeElementsSingular = args['makeSingular']
	finalJoiningWord = args['joinWord'] or "and"
	
	local type = args['type'] or 'sentence'
	local converter = converters[type]
	local elements = {}
	local listString = args[1]
	local strings = splitListString(listString)
	for i, str in ipairs(strings) do
		table.insert(elements, processElement(str))
	end
	return converter(elements)
end

return p