Modulo:ChronoSpine/stardate
Vai alla navigazione
Vai alla ricerca
La documentazione per questo modulo può essere creata in Modulo:ChronoSpine/stardate/man
--[[
Module:ChronoSpine/stardate
=============================
Purpose
-------
Parses the raw wikitext string an editor types into a `stellare`
parameter into a single normalised numeric stardate value.
Stardates are entirely independent of the real/partial date parsed by
Module:ChronoSpine/date: per the project briefing they are only ever
used as an in-year tie-breaker for sorting, never as a substitute for
a real date. Accordingly this module has NO dependency on
Module:ChronoSpine/date, matching the same "these two axes never
depend on each other" principle the briefing applies to `tempo` and
`fonte`.
Accepted formats
-----------------
Plain number 4789.6
Comma as decimal point 4789,6 (normalised to a dot)
With a display prefix DS 4789.6 (prefix stripped; case-
SD4789.6 insensitive; "DS "/"SD " both
accepted since different
fandoms/eras use either)
The "DS" shown to readers ("DS 4789.6") is added back at render time
from /i18n -- it is a display convention, not part of the stored
value, so it is stripped here rather than kept.
Return value convention
------------------------
Same convention as Module:ChronoSpine/date, for consistency:
On success: { ok = true, value = <number> }
On failure: { ok = false, raw = "<original string>", code = "<error code>" }
`code` is one of: "empty", "bad-format".
--]]
local M = {}
--[[
trim(text)
-----------
Private helper. Strips leading and trailing whitespace.
--]]
local function trim(text)
return text:match("^%s*(.-)%s*$")
end
--[[
strip_prefix(text)
--------------------
Private helper. Removes a leading "DS" or "SD" display prefix
(case-insensitive, with optional following whitespace), if present.
Returns just the remainder in that case -- if there was no prefix,
`text` is returned unchanged.
--]]
local function strip_prefix(text)
local remainder = text:match("^[Dd][Ss]%s*(.+)$")
if remainder then
return remainder
end
remainder = text:match("^[Ss][Dd]%s*(.+)$")
if remainder then
return remainder
end
return text
end
--[[
M.parse(raw)
-------------
Parses one raw stardate string into a normalised numeric value.
Parameters:
raw (string|nil) -- the raw `stellare` parameter value, exactly as
the editor typed it.
Returns:
(table) -- either { ok = true, value = <number> } or
{ ok = false, raw = raw, code = "..." }.
--]]
function M.parse(raw)
if raw ~= nil and type(raw) ~= "string" then
raw = tostring(raw)
end
if raw == nil then
return { ok = false, raw = raw, code = "empty" }
end
local text = trim(raw)
if text == "" then
return { ok = false, raw = raw, code = "empty" }
end
text = trim(strip_prefix(text))
if text == "" then
-- The prefix was the entire string ("DS" with nothing after it).
return { ok = false, raw = raw, code = "bad-format" }
end
-- Accept a comma as the decimal separator (common when editors
-- copy numbers typed with Italian formatting) by normalising it
-- to a dot -- but only when there is no dot already present, so
-- we never silently mangle a string that is malformed some other
-- way (e.g. "4.789,6").
if not text:find("%.", 1, true) then
text = text:gsub(",", ".")
end
-- After normalisation, the value must be a plain non-negative
-- decimal number: one or more digits, optionally a dot and more
-- digits.
if not text:match("^%d+%.?%d*$") then
return { ok = false, raw = raw, code = "bad-format" }
end
local value = tonumber(text)
if not value then
return { ok = false, raw = raw, code = "bad-format" }
end
return { ok = true, value = value }
end
return M