Module:foreign numerals

Hello, you have come here looking for the meaning of the word Module:foreign numerals. In DICTIOUS you will not only get to know all the dictionary meanings for the word Module:foreign numerals, but we will also tell you about its etymology, its characteristics and you will know how to say Module:foreign numerals in singular and plural. Everything you need to know about the word Module:foreign numerals you have here. The definition of the word Module:foreign numerals will help you to be more precise and correct when speaking or writing your texts. Knowing the definition ofModule:foreign numerals, as well as those of other words, enriches your vocabulary and provides you with more and better linguistic resources.

This module provides conversion to and from foreign numerals to native numerical values. It's partially redundant with Module:roman numerals.

Numeral system "From" function "To" function
Roman numerals from_Roman to_Roman
Armenian numerals from_Armenian
Hebrew numerals from_Hebrew to_Hebrew
Indian numerals from_Indian to_Indian

Each function may be called either from a template (see below) or from a module. "From" functions return native numerical values (of 'number' type), while "to" functions return strings.

Example:

{{#invoke:foreign numerals|to_Roman|2764}}

gives

MMDCCLXIV

And the reverse function:

{{#invoke:foreign numerals|from_Roman|MMDCCLXIV}}

gives

2764

This module serves as a backend to the templates {{R2A}} and {{A2R}}.


local u = require("Module:string utilities").char

local export = {}

-- Roman numerals

local from_Roman_tab = {
	M  = 1000; CM = 900; D  = 500; CD = 400;
	C  =  100; XC =  90; L  =  50; XL =  40;
	X  =   10; IX =   9; V  =   5; IV =   4;
	I  =    1;
}

local to_Roman_tab = {
	{ 1000, "M"  }; {  900, "CM" }; {  500, "D"  }; {  400, "CD" };
	{  100, "C"  }; {   90, "XC" }; {   50, "L"  }; {   40, "XL" };
	{   10, "X"  }; {    9, "IX" }; {    5, "V"  }; {    4, "IV" };
	{    1, "I"  };
}

local new_to_Roman_tab = {}

local overline = u(0x305)
local double_overline = u(0x33F)
-- Add overline and double-overline numerals. The table needs to be in reverse order, so do double overline first.
for _, v in ipairs(to_Roman_tab) do
	local number, symbol = unpack(v)
	if number > 1 then
		table.insert(new_to_Roman_tab, { number * 1000000, (symbol:gsub(".", "%1" .. double_overline)) })
	end
end
for _, v in ipairs(to_Roman_tab) do
	local number, symbol = unpack(v)
	if number > 1 then
		table.insert(new_to_Roman_tab, { number * 1000, (symbol:gsub(".", "%1" .. overline)) })
	end
end
for _, v in ipairs(to_Roman_tab) do
	table.insert(new_to_Roman_tab, v)
end

to_Roman_tab = new_to_Roman_tab

function export.to_Roman(numeral)
	if type(numeral) == 'table' then
		numeral = tonumber(numeral.args)
	else
		-- accept strings for use by ], which is invoked from ]
		-- with the number in string format to allow for very large numbers
		numeral = tonumber(numeral)
	end
	
	local output = {}
	for _, item in ipairs(to_Roman_tab) do
		local limit, letter = item, item
		while numeral >= limit do
			table.insert(output, letter)
			numeral = numeral - limit
		end
	end

	return table.concat(output)
end

function export.from_Roman(numeral)
	if type(numeral) == 'table' then
		numeral = numeral.args
	end
	if tonumber(numeral) then
		return tonumber(numeral)	
	end
	
	local accum = 0
	-- shame on Lua for having no regex alternations...

	while numeral ~= "" do
		local l2, l1 = numeral:sub(1, 2), numeral:sub(1, 1)
		if from_Roman_tab then
			accum = accum + from_Roman_tab
			numeral = numeral:sub(3)
		elseif from_Roman_tab then
			accum = accum + from_Roman_tab
			numeral = numeral:sub(2)
		else
			return nil
		end
	end
	
	return accum
end

-- Armenian numerals

local from_Armenian_tab = {
	 =    1;  =    2;  =    3;  =    4;  =    5;  =    6;  =    7;  =    8;  =    9;
	 =   10;  =   20;  =   30;  =   40;  =   50;  =   60;  =   70;  =   80;  =   90;
	 =  100;  =  200;  =  300;  =  400;  =  500;  =  600;  =  700;  =  800;  =  900;
	 = 1000;  = 2000;  = 3000;  = 4000;  = 5000;  = 6000;  = 7000;  = 8000;  = 9000;
}

function export.from_Armenian(numeral)
	if type(numeral) == 'table' then
		numeral = numeral.args
	end
	if tonumber(numeral) then
		return tonumber(numeral)	
	end

	local accum = 0
	for cp in mw.ustring.gcodepoint(numeral) do
		local value = from_Armenian_tab
		if value then
			accum = accum + value
		else
			return nil
		end
	end

	return accum	
end

-- Hebrew numerals

local from_Hebrew_tab = {
	 = 1,
	 = 2,
	 = 3,
	 = 4,
	 = 5,
	 = 6,
	 = 7,
	 = 8,
	 = 9,
	 = 10,
	 = 20,
	 = 20,
	 = 30,
	 = 40,
	 = 40,
	 = 50,
	 = 50,
	 = 60,
	 = 70,
	 = 80,
	 = 80,
	 = 90,
	 = 90,
	 = 100,
	 = 200,
	 = 300,
	 = 400,
}

local to_Hebrew_ones = { = '', 'א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט'}
local to_Hebrew_tens = { = '', 'י', 'כ', 'ל', 'מ', 'נ', 'ס', 'ע', 'פ', 'צ'}
local to_Hebrew_hundreds = { = '', 'ק', 'ר', 'ש', 'ת', 'תק', 'תר', 'תש', 'תת', 'תתק'}
local to_Hebrew_special = {
	 = 'טו',
	 = 'טז',
}

-- This only works for numbers such that 0 < value < 1000, because beyond that the logic gets complicated
function export.from_Hebrew(numeral)
	if type(numeral) == 'table' then
		numeral = numeral.args
	end
	if tonumber(numeral) then
		return tonumber(numeral)
	end

	local value = 0
	for c in mw.ustring.gmatch(numeral, '') do
		value = value + (from_Hebrew_tab or 0)
	end

	if value == 0 then
		return nil
	end

	return value
end

-- This only works for numbers such that 0 < value < 1000, because beyond that the logic gets complicated
function export.to_Hebrew(value, use_gershayim)
	if type(value) == 'table' then
		use_gershayim = value.args ~= '' and value.args
		value = value.args
	end
	if type(value) ~= 'number' then
		if tonumber(value) then
			value = tonumber(value)
		else
			return nil
		end
	end

	if value <= 0 or value >= 1000 then
		return nil
	end

	local tens_and_ones = value % 100
	local hundreds = to_Hebrew_hundreds
	if to_Hebrew_special then
		tens_and_ones = to_Hebrew_special
	else
		local ones = tens_and_ones % 10
		local tens = (tens_and_ones - ones) / 10
		tens_and_ones = to_Hebrew_tens .. to_Hebrew_ones
	end

	local numeral = hundreds .. tens_and_ones

	if use_gershayim then
		if mw.ustring.match(numeral, '^.$') then
			numeral = numeral .. '׳'
		else
			numeral = mw.ustring.gsub(numeral, '.$', '״%0')
		end
	end

	return numeral
end

-- Indian numerals

function export.from_Indian(numeral)
	if type(numeral) == 'table' then
		value = numeral.args
	else
		value = numeral
	end
	text = mw.ustring.gsub(
		tostring(value),
		'.',
		{
			 = '0',
			 = '1',
			 = '2',
			 = '3',
			 = '4',
			 = '5',
			 = '6',
			 = '7',
			 = '8',
			 = '9',
		}
	)
	return text
end

function export.to_Indian(numeral)
	if type(numeral) == 'table' then
		value = numeral.args
	else
		value = numeral
	end
	text = mw.ustring.gsub(
		tostring(value),
		'.',
		{
			 = '०',
			 = '१',
			 = '२',
			 = '३',
			 = '४',
			 = '५',
			 = '६',
			 = '७',
			 = '८',
			 = '९',
		}
	)
	return text
end

return export