Module:ParseList: Difference between revisions
No edit summary Tag: Reverted |
HiddenDragon (talk | contribs) (Added no margin version of htmlListNoBullets) |
||
(32 intermediate revisions by 3 users not shown) | |||
Line 2: | Line 2: | ||
local p = {} | local p = {} | ||
-- Config options, | -- Config options, set in main function | ||
local | local listDelimiters | ||
local | local makeElementsLinks | ||
local | local makeElementsPlural | ||
local | local makeElementsSingular | ||
local makeElementsLowercase | |||
local useTemplateOnElements | |||
local useTwoArgTemplateOnElements | |||
local textDelim | |||
local textLastDelim | |||
local function | local function splitListString(listString) | ||
local strings = {} | |||
for str in listString:gmatch("[^" .. listDelimiters .. "]+") do | |||
table.insert(strings, str:match("^%s*(.-)%s*$")) | |||
end | |||
return strings | |||
end | end | ||
-- This is a TWO-WAY conversion table of singular words and their corresponding | |||
-- plural form, for those that wouldn't be handled correctly by the automatic | |||
-- rules implemented further down below. Note that we don't need to cover most | |||
-- regular English words, as they're unlikely to ever be used with this module. | |||
-- The kind of stuff you want to add here is gameplay elements like classes, | |||
-- weapons, races, and so on. | |||
local specialPlurals = { | local specialPlurals = { | ||
-- Weapons | |||
Glaive = "Glaives", | |||
glaive = "glaives", | |||
Staff = "Staves", | |||
staff = "staves", | |||
-- Races | |||
Gith = "Gith", | |||
gith = "gith", | |||
Githyanki = "Githyanki", | |||
githyanki = "githyanki", | |||
Duergar = "Duergar", | |||
duergar = "duergar", | |||
Drow = "Drow", | |||
drow = "drow", | |||
Dragonborn = "Dragonborn", | |||
dragonborn = "dragonborn", | |||
-- Creature types | |||
Fey = "Fey", | |||
fey = "fey", | |||
Undead = "Undead", | |||
undead = "undead", | |||
} | } | ||
local function | -- Checks if str is equal to or ends in one of the keys in specialPlurals. | ||
-- Returns the pluralized version if so, otherwise nil. | |||
local function findSpecialPlural(str) | |||
if | for singular, plural in pairs(specialPlurals) do | ||
if str == singular then | |||
return plural | return plural | ||
end | end | ||
local len = #singular | |||
if | local suffix = str:sub(-len, -1) | ||
return | if (suffix == singular) then | ||
return str:sub(1, -len - 1) .. plural | |||
return str | end | ||
end | |||
end | |||
-- Checks if str is equal to or ends in one of the values in specialPlurals. | |||
-- Returns the singular version if so, otherwise nil. | |||
local function findSpecialSingular(str) | |||
for singular, plural in pairs(specialPlurals) do | |||
if str == plural then | |||
return singular | |||
end | |||
local len = #plural | |||
local suffix = str:sub(-len, -1) | |||
if suffix == plural then | |||
return str:sub(1, -len - 1) .. singular | |||
end | end | ||
end | end | ||
end | end | ||
local function | -- Checks for a special pluralization first, then implements these rules: | ||
local | -- ...f -> ...ves | ||
-- ...y -> ...ies | |||
-- ...s -> ...ses | |||
-- ...ch -> ...ches | |||
-- ...sh -> ...shes | |||
-- ... -> ...s | |||
local function makePlural(str) | |||
local sp = findSpecialPlural(str) | |||
if sp then | |||
return | return sp | ||
end | |||
local last1 = str:sub(-1) | |||
if last1 == "f" then | |||
local | return str:sub(1, -2) .. "ves" | ||
elseif last1 == "y" then | |||
result = result .. | return str:sub(1, -2) .. "ies" | ||
elseif last1 == "s" then | |||
result = result .. | return str .. "es" | ||
end | |||
local last2 = str:sub(-2) | |||
if last2 == "ch" or last2 == "sh" then | |||
return str .. "es" | |||
end | |||
return str .. "s" | |||
end | |||
-- Checks for a special singularization first, then implements these rules: | |||
-- ...ves -> ...f | |||
-- ...ies -> ...y | |||
-- ...ses -> ...s | |||
-- ...ches -> ...ch | |||
-- ...shes -> ...sh | |||
-- ...s -> ... | |||
-- ... -> ... | |||
local function makeSingular(str) | |||
local special = findSpecialSingular(str) | |||
if special then | |||
return special | |||
end | |||
local last3 = str:sub(-3) | |||
if last3 == "ves" then | |||
return str:sub(1, -4) .. "f" | |||
elseif last3 == "ies" then | |||
return str:sub(1, -4) .. "y" | |||
elseif last3 == "ses" then | |||
return str:sub(1, -3) | |||
end | |||
local last4 = str:sub(-4) | |||
if last4 == "ches" or last4 == "shes" then | |||
return str:sub(1, -3) | |||
end | |||
if str:sub(-1) == "s" then | |||
return str:sub(1, -2) | |||
end | |||
return str | |||
end | |||
-- Applies the various per-element transforms. Frame is needed for template | |||
-- expansion; it may be nil if template transforms won't be applied. | |||
local function processElement(str, frame) | |||
local original = str | |||
if makeElementsPlural then | |||
str = makePlural(str) | |||
elseif makeElementsSingular then | |||
str = makeSingular(str) | |||
end | |||
if makeElementsLowercase then | |||
str = str:lower() | |||
end | |||
if makeElementsLinks then | |||
return "[[" .. original .. "|" .. str .. "]]" | |||
elseif useTemplateOnElements then | |||
return frame:expandTemplate{ | |||
title = useTemplateOnElements, | |||
args = { str } | |||
} | |||
elseif useTwoArgTemplateOnElements then | |||
return frame:expandTemplate{ | |||
title = useTwoArgTemplateOnElements, | |||
args = { original, str } | |||
} | |||
end | |||
return str | |||
end | |||
-- These functions implement different output styles. The elements will have | |||
-- already gone through processElement() at this point, so they only need to be | |||
-- glued together to produce the desired style of listing format. | |||
local converters = { | |||
text = function (elements) | |||
local result = "" | |||
local count = #elements | |||
for i, str in ipairs(elements) do | |||
if i == 1 then | |||
result = str | |||
elseif i < count then | |||
result = result .. textDelim .. str | |||
else | |||
result = result .. textLastDelim .. str | |||
end | |||
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, | |||
htmlList = function (elements) | |||
local result = "<ul>\n" | |||
for i, str in ipairs(elements) do | |||
result = result .. "<li>" .. str .. "</li>\n" | |||
end | end | ||
return result .. "</ul>" | |||
end, | |||
htmlListNoBullets = function (elements) | |||
local result = "<ul style='list-style: none;'>\n" | |||
for i, str in ipairs(elements) do | |||
result = result .. "<li>" .. str .. "</li>\n" | |||
end | |||
return result .. "</ul>" | |||
end, | |||
htmlListNoBulletsOrMargin = function (elements) | |||
local result = "<ul style='list-style: none; margin: 0'>\n" | |||
for i, str in ipairs(elements) do | |||
result = result .. "<li>" .. str .. "</li>\n" | |||
end | |||
return result .. "</ul>" | |||
end, | |||
tableList = function (elements) | |||
local result = "<div class=\"bg3wiki-tablelist\">" | |||
for i, str in ipairs(elements) do | |||
result = result .. str .. "\n" | |||
end | |||
return result .. "</div>" | |||
end, | |||
none = function (elements) | |||
local result = "" | |||
for i, str in ipairs(elements) do | |||
result = result .. str | |||
end | |||
return result | |||
end, | |||
} | |||
function p.main(frame) | |||
local args = getArgs(frame, { frameOnly = true }) | |||
return p._main(args, frame) | |||
end | end | ||
function p. | -- Frame is needed for template expansion; may be nil if the useTemplate and | ||
-- useTemplate2 args are nil. | |||
function p._main(args, frame) | |||
listDelimiters = args['delimiter'] or "," | |||
makeElementsLinks = args['makeLinks'] | |||
makeElementsPlural = args['makePlural'] | |||
makeElementsSingular = args['makeSingular'] | |||
makeElementsLowercase = args['makeLowercase'] | |||
useTemplateOnElements = args['useTemplate'] | |||
useTwoArgTemplateOnElements = args['useTemplate2'] | |||
textDelim = args['textDelim'] | |||
if textDelim then | |||
textLastDelim = args['textLastDelim'] or textDelim | |||
else | |||
textDelim = ', ' | |||
textLastDelim = args['textLastDelim'] or ', and ' | |||
end | |||
local style = args['style'] or args['type'] or 'text' | |||
local converter = converters[style] | |||
local elements = {} | |||
local listString = args[1] | |||
local strings = splitListString(listString) | |||
for i, str in ipairs(strings) do | |||
table.insert(elements, processElement(str, frame)) | |||
end | |||
return converter(elements) | |||
end | end | ||
return p | return p |
Latest revision as of 23:07, 11 October 2024
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 |
useTemplate |
(empty) |
If provided, will use the provided template on each element, i.e., turn every This is done after any transforms like plural, singular and lowercase. E.g., the list element "Apple" would become |
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 |
textDelim |
', ' |
If Setting this causes the default value for Note that the default value is not just a comma; it's a comma followed by a space character. |
textLastDelim |
(conditional) |
If If If Note: The use of |
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, Wizard |
htmlList
|
|
htmlListNoBullets
|
|
htmlListNoBulletsOrMargin
|
|
tableList
|
Fighter
Cleric Wizard |
none
|
FighterClericWizard |
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:
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:
Make Plural Links, end with "or"
{{#invoke: ParseList | main | Fighter, Cleric, Wizard | makeLinks = yes | makePlural = yes | textLastDelim = <nowiki>, or </nowiki> }}
Result:
Make Plural Links, turn into HTML list
{{#invoke: ParseList | main | Fighter, Cleric, Wizard | makeLinks = yes | makePlural = yes | style = htmlList }}
Result:
local getArgs = require('Module:Arguments').getArgs
local p = {}
-- Config options, set in main function
local listDelimiters
local makeElementsLinks
local makeElementsPlural
local makeElementsSingular
local makeElementsLowercase
local useTemplateOnElements
local useTwoArgTemplateOnElements
local textDelim
local textLastDelim
local function splitListString(listString)
local strings = {}
for str in listString:gmatch("[^" .. listDelimiters .. "]+") do
table.insert(strings, str:match("^%s*(.-)%s*$"))
end
return strings
end
-- This is a TWO-WAY conversion table of singular words and their corresponding
-- plural form, for those that wouldn't be handled correctly by the automatic
-- rules implemented further down below. Note that we don't need to cover most
-- regular English words, as they're unlikely to ever be used with this module.
-- The kind of stuff you want to add here is gameplay elements like classes,
-- weapons, races, and so on.
local specialPlurals = {
-- Weapons
Glaive = "Glaives",
glaive = "glaives",
Staff = "Staves",
staff = "staves",
-- Races
Gith = "Gith",
gith = "gith",
Githyanki = "Githyanki",
githyanki = "githyanki",
Duergar = "Duergar",
duergar = "duergar",
Drow = "Drow",
drow = "drow",
Dragonborn = "Dragonborn",
dragonborn = "dragonborn",
-- Creature types
Fey = "Fey",
fey = "fey",
Undead = "Undead",
undead = "undead",
}
-- Checks if str is equal to or ends in one of the keys in specialPlurals.
-- Returns the pluralized version if so, otherwise nil.
local function findSpecialPlural(str)
for singular, plural in pairs(specialPlurals) do
if str == singular then
return plural
end
local len = #singular
local suffix = str:sub(-len, -1)
if (suffix == singular) then
return str:sub(1, -len - 1) .. plural
end
end
end
-- Checks if str is equal to or ends in one of the values in specialPlurals.
-- Returns the singular version if so, otherwise nil.
local function findSpecialSingular(str)
for singular, plural in pairs(specialPlurals) do
if str == plural then
return singular
end
local len = #plural
local suffix = str:sub(-len, -1)
if suffix == plural then
return str:sub(1, -len - 1) .. singular
end
end
end
-- Checks for a special pluralization first, then implements these rules:
-- ...f -> ...ves
-- ...y -> ...ies
-- ...s -> ...ses
-- ...ch -> ...ches
-- ...sh -> ...shes
-- ... -> ...s
local function makePlural(str)
local sp = findSpecialPlural(str)
if sp then
return sp
end
local last1 = str:sub(-1)
if last1 == "f" then
return str:sub(1, -2) .. "ves"
elseif last1 == "y" then
return str:sub(1, -2) .. "ies"
elseif last1 == "s" then
return str .. "es"
end
local last2 = str:sub(-2)
if last2 == "ch" or last2 == "sh" then
return str .. "es"
end
return str .. "s"
end
-- Checks for a special singularization first, then implements these rules:
-- ...ves -> ...f
-- ...ies -> ...y
-- ...ses -> ...s
-- ...ches -> ...ch
-- ...shes -> ...sh
-- ...s -> ...
-- ... -> ...
local function makeSingular(str)
local special = findSpecialSingular(str)
if special then
return special
end
local last3 = str:sub(-3)
if last3 == "ves" then
return str:sub(1, -4) .. "f"
elseif last3 == "ies" then
return str:sub(1, -4) .. "y"
elseif last3 == "ses" then
return str:sub(1, -3)
end
local last4 = str:sub(-4)
if last4 == "ches" or last4 == "shes" then
return str:sub(1, -3)
end
if str:sub(-1) == "s" then
return str:sub(1, -2)
end
return str
end
-- Applies the various per-element transforms. Frame is needed for template
-- expansion; it may be nil if template transforms won't be applied.
local function processElement(str, frame)
local original = str
if makeElementsPlural then
str = makePlural(str)
elseif makeElementsSingular then
str = makeSingular(str)
end
if makeElementsLowercase then
str = str:lower()
end
if makeElementsLinks then
return "[[" .. original .. "|" .. str .. "]]"
elseif useTemplateOnElements then
return frame:expandTemplate{
title = useTemplateOnElements,
args = { str }
}
elseif useTwoArgTemplateOnElements then
return frame:expandTemplate{
title = useTwoArgTemplateOnElements,
args = { original, str }
}
end
return str
end
-- These functions implement different output styles. The elements will have
-- already gone through processElement() at this point, so they only need to be
-- glued together to produce the desired style of listing format.
local converters = {
text = function (elements)
local result = ""
local count = #elements
for i, str in ipairs(elements) do
if i == 1 then
result = str
elseif i < count then
result = result .. textDelim .. str
else
result = result .. textLastDelim .. str
end
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,
htmlList = function (elements)
local result = "<ul>\n"
for i, str in ipairs(elements) do
result = result .. "<li>" .. str .. "</li>\n"
end
return result .. "</ul>"
end,
htmlListNoBullets = function (elements)
local result = "<ul style='list-style: none;'>\n"
for i, str in ipairs(elements) do
result = result .. "<li>" .. str .. "</li>\n"
end
return result .. "</ul>"
end,
htmlListNoBulletsOrMargin = function (elements)
local result = "<ul style='list-style: none; margin: 0'>\n"
for i, str in ipairs(elements) do
result = result .. "<li>" .. str .. "</li>\n"
end
return result .. "</ul>"
end,
tableList = function (elements)
local result = "<div class=\"bg3wiki-tablelist\">"
for i, str in ipairs(elements) do
result = result .. str .. "\n"
end
return result .. "</div>"
end,
none = function (elements)
local result = ""
for i, str in ipairs(elements) do
result = result .. str
end
return result
end,
}
function p.main(frame)
local args = getArgs(frame, { frameOnly = true })
return p._main(args, frame)
end
-- Frame is needed for template expansion; may be nil if the useTemplate and
-- useTemplate2 args are nil.
function p._main(args, frame)
listDelimiters = args['delimiter'] or ","
makeElementsLinks = args['makeLinks']
makeElementsPlural = args['makePlural']
makeElementsSingular = args['makeSingular']
makeElementsLowercase = args['makeLowercase']
useTemplateOnElements = args['useTemplate']
useTwoArgTemplateOnElements = args['useTemplate2']
textDelim = args['textDelim']
if textDelim then
textLastDelim = args['textLastDelim'] or textDelim
else
textDelim = ', '
textLastDelim = args['textLastDelim'] or ', and '
end
local style = args['style'] or args['type'] or 'text'
local converter = converters[style]
local elements = {}
local listString = args[1]
local strings = splitListString(listString)
for i, str in ipairs(strings) do
table.insert(elements, processElement(str, frame))
end
return converter(elements)
end
return p