Module used by {{Normalize volume and edition}}
| This module is currently under extended confirmed protection. Extended confirmed protection prevents edits from all unregistered editors and registered users with fewer than 30 days tenure and 500 edits. The policy on community use specifies that extended confirmed protection can be applied to combat disruption, if semi-protection has proven to be ineffective. Extended confirmed protection may also be applied to enforce arbitration sanctions. Please discuss any changes on the talk page; you may submit an edit request to ask for uncontroversial changes supported by consensus. |
Module used by {{Normalize volume and edition}}
{{#invoke:Normalize volume and edition|volume/edition|string}}
local p = {}
-- Master dictionary mapping written words, ordinals, and foreign terms to digits
local text_to_num = {
["one"] = "1", ["first"] = "1", ["1st"] = "1", ["i"] = "1",
["two"] = "2", ["second"] = "2", ["2nd"] = "2", ["ii"] = "2",
["three"] = "3", ["third"] = "3", ["3rd"] = "3", ["iii"] = "3",
["four"] = "4", ["fourth"] = "4", ["4th"] = "4", ["iv"] = "4",
["five"] = "5", ["fifth"] = "5", ["5th"] = "5", ["v"] = "5",
["six"] = "6", ["sixth"] = "6", ["6th"] = "6", ["vi"] = "6",
["seven"] = "7", ["seventh"] = "7", ["7th"] = "7", ["vii"] = "7",
["eight"] = "8", ["eighth"] = "8", ["8th"] = "8", ["viii"] = "8",
["nine"] = "9", ["ninth"] = "9", ["9th"] = "9", ["ix"] = "9",
["ten"] = "10", ["tenth"] = "10", ["10th"] = "10", ["x"] = "10",
["eleventh"] = "11", ["twelfth"] = "12", ["thirteenth"] = "13",
["fourteenth"] = "14", ["fifteenth"] = "15", ["sixteenth"] = "16",
-- Foreign Additions (Spanish, French, German, Dutch, Italian, Latin)
-- "One" / "First"
["uno"] = "1", ["un"] = "1", ["una"] = "1", ["ein"] = "1", ["eine"] = "1", ["eins"] = "1",
["een"] = "1", ["primus"] = "1", ["prima"] = "1", ["primo"] = "1", ["primer"] = "1",
["primera"] = "1", ["premier"] = "1", ["première"] = "1", ["erste"] = "1",
["eerste"] = "1", ["1ª"] = "1", ["初版"] = "1", ["第1巻"] = "1",
-- "Two" / "Second"
["dos"] = "2", ["deux"] = "2", ["zwei"] = "2", ["twee"] = "2",
["secundus"] = "2", ["secunda"] = "2", ["secundo"] = "2", ["segunda"] = "2",
["deuxième"] = "2", ["zweite"] = "2", ["tweede"] = "2", ["2ª"] = "2",
-- "Three" / "Third"
["tres"] = "3", ["trois"] = "3", ["drei"] = "3", ["drie"] = "3",
["tertius"] = "3", ["terza"] = "3", ["troisième"] = "3", ["dritte"] = "3", ["derde"] = "3",
-- "Four" / "Fourth"
["cuatro"] = "4", ["quatre"] = "4", ["vier"] = "4",
["cuarto"] = "4", ["quatrième"] = "4", ["vierte"] = "4",
-- "Five" / "Fifth"
["cinco"] = "5", ["cinq"] = "5", ["fünf"] = "5", ["vijf"] = "5",
["quinto"] = "5", ["cinquième"] = "5", ["fünfte"] = "5"
}
-- Simple Roman Numeral to Integer converter
local function roman_to_int(roman)
local map = {i = 1, v = 5, x = 10, l = 50, c = 100}
local total = 0
local prev = 0
-- iterate backwards through the string
for i = mw.ustring.len(roman), 1, -1 do
local char = mw.ustring.sub(roman, i, i)
local val = map[char]
if not val then return nil end -- invalid character found
if val < prev then
total = total - val
else
total = total + val
end
prev = val
end
return tostring(total)
end
local function normalize_string(input_str, type_flag)
if not input_str or input_str == "" then return "" end
local s = mw.ustring.lower(input_str)
-- PREVENT THE ROMAN NUMERAL TRAP:
if type_flag == "volume" then
s = mw.ustring.gsub(s, "^v%.%s*(%w+)", "%1")
s = mw.ustring.gsub(s, "^v%s+(%w+)", "%1")
end
-- STRIP ORDINAL SUFFIXES GLOBALLY (e.g. 113th -> 113, 22nd -> 22)
-- Using %f[%s%p] frontier pattern to ensure we only strip suffixes at the end of a word
s = mw.ustring.gsub(s, "(%d+)st%f[%s%p]", "%1")
s = mw.ustring.gsub(s, "(%d+)nd%f[%s%p]", "%1")
s = mw.ustring.gsub(s, "(%d+)rd%f[%s%p]", "%1")
s = mw.ustring.gsub(s, "(%d+)th%f[%s%p]", "%1")
-- CONVERT PARENTHESIZED PARTS TO DECIMALS: "3(1)" -> "3.1"
s = mw.ustring.gsub(s, "(%d)%s*%((%d+)%)", "%1.%2")
-- PROTECT DECIMALS
s = mw.ustring.gsub(s, "(%d)%.(%d)", "%1ZZDOTZZ%2")
s = mw.ustring.gsub(s, "(%d)%.(%d)", "%1ZZDOTZZ%2")
-- PROTECT RANGES (Replace hyphens/en-dashes between numbers with a safe string)
s = mw.ustring.gsub(s, "(%d+)%s*[-–]%s*(%d+)", "%1ZZDASHZZ%2")
-- Convert all remaining punctuation to spaces
s = mw.ustring.gsub(s, "[%p]", " ")
-- RESTORE DECIMALS AND RANGES (Standardizing ranges to en-dash)
s = mw.ustring.gsub(s, "ZZDOTZZ", ".")
s = mw.ustring.gsub(s, "ZZDASHZZ", "–")
-- SQUISH HANGING LETTERS
s = " " .. s .. " "
s = mw.ustring.gsub(s, "(%d)%s+([a-z])%s+", "%1%2 ")
s = mw.ustring.match(s, "^%s*(.-)%s*$")
-- Break the string into individual words/tokens
for word in mw.ustring.gmatch(s, "%S+") do
-- 1. Check Dictionary (Catches words, foreign ordinals, single letters 'i', 'v')
if text_to_num[word] then
return text_to_num[word]
end
-- 2. Check Roman Numerals (Only allows standard roman characters)
if mw.ustring.match(word, "^[ivxlc]+$") then
local arabic = roman_to_int(word)
if arabic then return arabic end
end
-- 3. Check for standard Numbers, Decimals, or "Number+Letter" (e.g., 3, 3.1, 3a)
if mw.ustring.match(word, "^%d+%.?%d*[a-z]?$") then
return word
end
-- 3.5 Check for protected Ranges (e.g., 1–3)
if mw.ustring.match(word, "^%d+–%d+$") then
return word
end
-- 4. Check for letter-first alphanumeric volumes (e.g., "A1")
if mw.ustring.match(word, "^[a-z]%d+$") then
return mw.ustring.upper(word)
end
-- 5. Volume single-letter fallback (e.g., "A", "b")
if type_flag == "volume" then
if mw.ustring.match(word, "^[a-z]$") and word ~= "v" then
return mw.ustring.upper(word)
end
end
end
-- Return the original input if nothing recognized is found
return mw.text.trim(input_str)
end
function p.volume(frame)
local args = frame.args[1] and frame.args or frame:getParent().args
return normalize_string(args[1], "volume")
end
function p.edition(frame)
local args = frame.args[1] and frame.args or frame:getParent().args
return normalize_string(args[1], "edition")
end
return p
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.