Модуль:Height: различия между версиями
Материал из проекта «Повелитель Тайн Вики»
Дополнительные действия
imported>Import Импорт с англ. вики (CC BY-SA) |
Admin (обсуждение | вклад) fix: Height robust |
||
| Строка 7: | Строка 7: | ||
s = mw.text.trim(tostring(s)):gsub(',', '.') | s = mw.text.trim(tostring(s)):gsub(',', '.') | ||
return tonumber(s) | return tonumber(s) | ||
end | |||
-- Imperial value with optional fraction: "7", "7.5", "7+1/2", "7 1/2", "7_1/2", "7-1/2", "7½", "1/2", {{frac}} output. | |||
local vulgar = { ['½'] = 0.5, ['¼'] = 0.25, ['¾'] = 0.75, ['⅓'] = 1/3, ['⅔'] = 2/3, ['⅛'] = 0.125, ['⅜'] = 0.375, ['⅝'] = 0.625, ['⅞'] = 0.875 } | |||
local function inum(s) | |||
if s == nil then return nil end | |||
s = mw.text.trim(tostring(s)) | |||
s = s:gsub('<[^>]*>', ''):gsub('⁄', '/'):gsub('⁄', '/'):gsub('⁄', '/') | |||
s = mw.text.trim(s) | |||
local v = num(s) | |||
if v then return v end | |||
for ch, val in pairs(vulgar) do | |||
local u = s:match('^(%d*)%s*' .. ch .. '$') | |||
if u then return (tonumber(u) or 0) + val end | |||
end | |||
local u, n, d = s:match('^(%d+)%s*[%+%s_%-]%s*(%d+)%s*/%s*(%d+)$') | |||
if not u then n, d = s:match('^(%d+)%s*/%s*(%d+)$'); u = 0 end | |||
if n and tonumber(d) and tonumber(d) ~= 0 then return tonumber(u) + tonumber(n) / tonumber(d) end | |||
return nil | |||
end | end | ||
| Строка 53: | Строка 72: | ||
vals = parseRange(cm); unit = 'cm' | vals = parseRange(cm); unit = 'cm' | ||
elseif ft or inch then | elseif ft or inch then | ||
local | local f, i = inum(ft), inum(inch) | ||
local imp = ( | -- unparseable input (e.g. template/doc page without values): return it as is instead of a Lua error | ||
if (ft and f == nil) or (inch and i == nil) then | |||
return mw.text.trim((ft and (ft .. ' фт') or '') .. ' ' .. (inch and (inch .. ' дюйм.') or '')) | |||
end | |||
local mtr = ((f or 0) * 12 + (i or 0)) * 0.0254 | |||
local imp = (f and (fmt(f) .. ' фт') or '') .. ((i and i ~= 0) and (' ' .. fmt(i, 2) .. ' дюйм.') or '') | |||
if args.out == 'cm' then return fmt(mtr * 100, 0) .. ' см (' .. mw.text.trim(imp) .. ')' end | |||
return fmt(mtr, 2) .. ' м (' .. mw.text.trim(imp) .. ')' | return fmt(mtr, 2) .. ' м (' .. mw.text.trim(imp) .. ')' | ||
else | else | ||
| Строка 71: | Строка 96: | ||
return p | return p | ||
Версия от 03:18, 1 ноября 2026
-- [ru] Height formatting for {{Height}}: metric first, imperial in brackets, Russian units.
-- {{Height|m=1.73}} -> 1,73 м (5 фт 8 дюйм.) {{Height|m=1.8 to 1.9}} -> 1,8–1,9 м (5 фт 11 дюйм. – 6 фт 3 дюйм.)
local p = {}
local function num(s)
if s == nil then return nil end
s = mw.text.trim(tostring(s)):gsub(',', '.')
return tonumber(s)
end
-- Imperial value with optional fraction: "7", "7.5", "7+1/2", "7 1/2", "7_1/2", "7-1/2", "7½", "1/2", {{frac}} output.
local vulgar = { ['½'] = 0.5, ['¼'] = 0.25, ['¾'] = 0.75, ['⅓'] = 1/3, ['⅔'] = 2/3, ['⅛'] = 0.125, ['⅜'] = 0.375, ['⅝'] = 0.625, ['⅞'] = 0.875 }
local function inum(s)
if s == nil then return nil end
s = mw.text.trim(tostring(s))
s = s:gsub('<[^>]*>', ''):gsub('⁄', '/'):gsub('⁄', '/'):gsub('⁄', '/')
s = mw.text.trim(s)
local v = num(s)
if v then return v end
for ch, val in pairs(vulgar) do
local u = s:match('^(%d*)%s*' .. ch .. '$')
if u then return (tonumber(u) or 0) + val end
end
local u, n, d = s:match('^(%d+)%s*[%+%s_%-]%s*(%d+)%s*/%s*(%d+)$')
if not u then n, d = s:match('^(%d+)%s*/%s*(%d+)$'); u = 0 end
if n and tonumber(d) and tonumber(d) ~= 0 then return tonumber(u) + tonumber(n) / tonumber(d) end
return nil
end
local function fmt(x, digits)
local s
if digits then s = string.format('%.' .. digits .. 'f', x) else s = tostring(x) end
if s:find('%.') then s = s:gsub('0+$', ''):gsub('%.$', '') end
return (s:gsub('%.', ','))
end
local function ftin(meters)
local inches = meters / 0.0254
local ft = math.floor(inches / 12)
local inch = math.floor(inches - ft * 12 + 0.5)
if inch == 12 then ft = ft + 1; inch = 0 end
if inch == 0 then return ft .. ' фт' end
return ft .. ' фт ' .. inch .. ' дюйм.'
end
local function parseRange(s)
if s == nil or mw.text.trim(s) == '' then return nil end
local a, b = s:match('^%s*([%d%.,]+)%s*to%s*([%d%.,]+)%s*$')
if not a then a, b = s:match('^%s*([%d%.,]+)%s*[%-–—]%s*([%d%.,]+)%s*$') end
if a then return { num(a), num(b) } end
local v = num(s)
if v then return { v } end
return nil
end
function p.height(frame)
local args = frame:getParent().args
local function g(...)
for _, k in ipairs({...}) do
local v = args[k]
if v and mw.text.trim(v) ~= '' then return v end
end
end
local m = g('meter', 'meters', 'metre', 'metres', 'm')
local cm = g('centimeter', 'centimeters', 'centimetre', 'centimetres', 'cm')
local ft = g('foot', 'feet', 'ft')
local inch = g('inch', 'inches', 'in')
local vals, unit
if m then
vals = parseRange(m); unit = 'm'
elseif cm then
vals = parseRange(cm); unit = 'cm'
elseif ft or inch then
local f, i = inum(ft), inum(inch)
-- unparseable input (e.g. template/doc page without values): return it as is instead of a Lua error
if (ft and f == nil) or (inch and i == nil) then
return mw.text.trim((ft and (ft .. ' фт') or '') .. ' ' .. (inch and (inch .. ' дюйм.') or ''))
end
local mtr = ((f or 0) * 12 + (i or 0)) * 0.0254
local imp = (f and (fmt(f) .. ' фт') or '') .. ((i and i ~= 0) and (' ' .. fmt(i, 2) .. ' дюйм.') or '')
if args.out == 'cm' then return fmt(mtr * 100, 0) .. ' см (' .. mw.text.trim(imp) .. ')' end
return fmt(mtr, 2) .. ' м (' .. mw.text.trim(imp) .. ')'
else
return ''
end
if vals == nil then return m or cm end
local metric, imp = {}, {}
for i, v in ipairs(vals) do
local meters = unit == 'cm' and v / 100 or v
metric[i] = unit == 'cm' and fmt(v) or fmt(v)
imp[i] = ftin(meters)
end
local u = unit == 'cm' and ' см' or ' м'
return table.concat(metric, '–') .. u .. ' (' .. table.concat(imp, ' – ') .. ')'
end
return p