יחידה:שם המספר

ניתן ליצור תיעוד על היחידה הזאת בדף יחידה:שם המספר/תיעוד

--------------------------------------------------------------------------------------------------------------
-- 
--------------------------------------------------------------------------------------------------------------
-- For reference see:
-- [1]	https://hebrew-academy.org.il/topic/hahlatot/grammardecisions/terminology-ordinance/4-3-השימוש-בשם-המספר/
-- [2]	https://hebrew-academy.org.il/wp-content/uploads/meeting20.pdf#page=19
-- [3]	https://hebrew-academy.org.il/wp-content/uploads/Intro-zihronot-5.pdf#page=16
-- [4]	https://hebrew-academy.org.il/wp-content/uploads/meeting92.pdf#page=6
-- [5]	https://hebrew-academy.org.il/wp-content/uploads/meeting164-165.pdf#page=14
-- [6]	https://hebrew-academy.org.il/wp-content/uploads/meeting216.pdf#page=15
-- [7]	https://hebrew-academy.org.il/wp-content/uploads/meeting240.pdf#page=7
-- [8]	https://hebrew-academy.org.il/wp-content/uploads/meeting309.pdf#page=8
-- [9]	https://hebrew-academy.org.il/wp-content/uploads/meeting314.pdf#page=2
-- [10]	https://hebrew-academy.org.il/wp-content/uploads/meeting-329.pdf#page=9
--------------------------------------------------------------------------------------------------------------

local m_cardinal = {
	[0] = 'אפס',
	[1] = 'אחד',
	[2] = 'שניים',
	[3] = 'שלושה',
	[4] = 'ארבעה',
	[5] = 'חמישה',
	[6] = 'שישה',
	[7] = 'שבעה',
	[8] = 'שמונה',
	[9] = 'תשעה',
	[10] = 'עשרה',
	[11] = 'עשר' --for numbers in the range 10-19
}

local f_cardinal = {
	[0] = 'אפס',
	[1] = 'אחת',
	[2] = 'שתיים',
	[3] = 'שלוש',
	[4] = 'ארבע',
	[5] = 'חמש',
	[6] = 'שש',
	[7] = 'שבע',
	[8] = 'שמונה',
	[9] = 'תשע',
	[10] = 'עשר',
	[11] = 'עשרה' --for numbers in the range 10-19
}

local m_ordinal = {
	[0] = 'אפס',
	[1] = 'ראשון',
	[2] = 'שני',
	[3] = 'שלישי',
	[4] = 'רביעי',
	[5] = 'חמישי',
	[6] = 'שישי',
	[7] = 'שביעי',
	[8] = 'שמיני',
	[9] = 'תשיעי',
	[10] = 'עשירי',
	[11] = 'עשירית'
}

local f_ordinal = {
	[0] = 'אפס',
	[1] = 'ראשונה',
	[2] = 'שנייה',
	[3] = 'שלישית',
	[4] = 'רביעית',
	[5] = 'חמישית',
	[6] = 'שישית',
	[7] = 'שביעית',
	[8] = 'שמינית',
	[9] = 'תשיעית',
	[10] = 'עשירית',
	[11] = 'עשירי'
}

local m_construct = {
	[1] = 'אחד',
	[2] = 'שני',
	[3] = 'שלושת',
	[4] = 'ארבעת',
	[5] = 'חמשת',
	[6] = 'ששת',
	[7] = 'שבעת',
	[8] = 'שמונת',
	[9] = 'תשעת',
	[10] = 'עשרת',
	[11] = 'עשר'
}

local thousands = {
	[1] = 'אלף',
	[2] = 'אלפיים',
	[3] = 'שלושת אלפים',
	[4] = 'ארבעת אלפים',
	[5] = 'חמשת אלפים',
	[6] = 'ששת אלפים',
	[7] = 'שבעת אלפים',
	[8] = 'שמונת אלפים',
	[9] = 'תשעת אלפים',
	[10] = 'עשרת אלפים',
}

local f_construct = {
	[1] = 'אחת',
	[2] = 'שתי',
	[3] = 'שלוש',
	[4] = 'ארבע',
	[5] = 'חמש',
	[6] = 'שש',
	[7] = 'שבע',
	[8] = 'שמונה',
	[9] = 'תשע',
	[10] = 'עשר',
	[11] = 'עשרה'
}

local tens = {
	[1] = 'עשרה',
	[2] = 'עשרים',
	[3] = 'שלושים',
	[4] = 'ארבעים',
	[5] = 'חמישים',
	[6] = 'שישים',
	[7] = 'שבעים',
	[8] = 'שמונים',
	[9] = 'תשעים'
}

local specials = {
	[11] = 'עשתי עשר',
	[12] = 'תריסר',
	[200] = 'מאתיים',
	[2000] = 'אלפיים',
	[10000] = 'רבבה'
}

local others = {
	[1] = 'פרט',
	[2] = 'זוג',
	[3] = 'שלישיה',
	[4] = 'רביעיה',
	[5] = 'חמישיה',
	[6] = 'שישיה',
	[7] = 'שביעיה',
	[8] = 'שמיניה',
	[9] = 'תשיעיה',
	[10] = 'עשיריה'
}

local fractions = {
	[1] = 'יחידה',
	[2] = 'חצי',
	[3] = 'שליש',
	[4] = 'רבע',
	[5] = 'חמישית',
	[6] = 'שישית',
	[7] = 'שביעית',
	[8] = 'שמינית',
	[9] = 'תשיעית',
	[10] = 'עשירית',
	[100] = 'מאית',
	[1000] = 'אלפית'
}

local groups = {
	[1] = 'אלף',
	[2] = 'מיליון',
	[3] = 'מיליארד',
	[4] = 'טריליון',
	[5] = 'קוודריליון',
	[6] = 'קווינטיליון'
}

local groups_plurals = {
	[1] = 'אחדות',
	[2] = 'עשרות',
	[3] = 'מאות',
	[4] = 'אלפים',
	[5] = 'עשרות אלפים',
	[6] = 'מאות אלפים',
	[7] = 'מיליונים',
	[8] = 'עשרות מיליונים',
	[9] = 'מאות מיליונים',
	[10] = 'מיליארדים',
	[11] = 'עשרות מיליארדים',
	[12] = 'מאות מיליארדים',
	[13] = 'טריליונים',
	[14] = 'עשרות טריליונים',
	[15] = 'מאות טריליונים',
	[16] = 'קוודריליונים',
	[17] = 'עשרות קוודריליונים',
	[18] = 'מאות קוודריליונים',
	[19] = 'קווינטיליונים',
	[20] = 'עשרות קווינטיליונים',
	[21] = 'מאות קווינטיליונים'
}

-- input: list of zero or more variables, e.g. set('a', 1, 7)
-- returns a table keyed by the values of all non-nul params, each with value true:
--  { ['a'] = true, 1 = true, 7 = true }
local function set(...)
   local t = {}
   for _,k in ipairs({...}) do t[k] = true end
   return t
end

--איחוד של שתי טבלאות: בהמשכה של הטבלה הראשונה נכתבת הטבלה השנייה 
local function tableConcat(primary, secondary)
    for i=1,#secondary do
        primary[#primary+1] = secondary[i]
    end
    return primary
end

--הפונקציה מקבלת כקלט טבלה של מספרים בני מילה אחת כל אחד, ומשרשרת את איבריה למחרוזת שהיא מספר אחד בן מילים אחדות
--דוגמה: טבלה שאיבריה מאה, שלושים, שבע תהפוך למחרוזת מאה שלושים ושבע
--דוגמה: טבלה שאיבריה מאה, שלושים, שבע, אלף תהפוך למחרוזת מאה שלושים ושבעה אלף
local function stringify(t)
	local result = '' --תוצאת הפונקציה
	local v --האיבר הבא בטבלה
	local first=1
	if #t > 1 then
		for _,name in pairs(t) do
			if result ~= '' then result=result..' ' end --הוספת מרווח בין מילה למילה
			if next(t,_) == nil then 
			    v= ''
			else 
			    v=t[next(t,_)] --האיבר הבא בטבלה    
			end
			if (v == '' and name ~= 'אלף' and name ~= 'אלפים' and name ~= 'מיליון' and name ~= 'מיליארד') or ((v == 'אלף' or v == 'מיליון' or v == 'מיליארד' ) and first == 0 ) then
				result = result..'ו'..name --לפני הספרה האחרונה יש להוסיף את ו"ו החיבור
			else
				 first = 0
				result = result..name
			end
		end
	else --בטבלת הקלט יש רק איבר אחד
		result = t[1]
	end
	
	return result
end

--הפונקציה מקבלת כקלט מנה של עד שלוש ספרות, המיקום שלהן במספר וטבלת ההמרה המתאימה, וממירה את הספרות למילים
--position - מיקום הספרות במספר השלם
--digit3 - ספרת המאות; digit2 - ספרת העשרות; digit1 - ספרת היחידות
--ones - טבלת ההמרה
local function triadicGroup(mispar, position, digit3, digit2, digit1, ones)
	local res = {} --תוצרת ההמרה

	if math.fmod(position, 3) == 2 and digit3 ~= 0 then --המרת ספרת המאות
		if digit3 == 1 then
			table.insert(res, 'מאה')
		elseif digit3 == 2 then
			table.insert(res, 'מאתיים')
		else
			table.insert(res, f_cardinal[digit3] .. ' ' .. 'מאות')
		end
	end
	if math.fmod(position, 3) >= 1 and digit2 ~= 0 then --המרת ספרת העשרות
	    if tonumber(mispar) == 10 then
	       table.insert(res, ones[10]) 
		elseif digit2 ~= 1 or (digit1 == 0 and position ~= 4) then 
			table.insert(res, tens[digit2])
		end
	end
	if math.fmod(position, 3) >= 0 and digit1 ~= 0 then --המרת ספרת היחידות
		if digit2 == 1 then --כשספרת העשרות היא 1 נדרש טיפול מיוחד
			table.insert(res, ones[digit1]..'־'..ones[11])
		elseif digit1 ~= 1 or (digit1 == 1 and (digit2 ~= 0 or digit3 ~= 0)) or math.floor(position / 3) == 0 then
			if not (math.floor(position / 3) == 1 and digit3 == 0 and ((digit1 ~= 0 and digit2 == 0) or  (digit1 == 0 and digit2 == 1))) then --החרגת אלפים בין אלף לעשרת אלפים
				if position > 3 then
			       table.insert(res, m_cardinal[digit1]) --השמות אלף, מיליון וכולי הם ממין זכר, בלי תלות במין של המספר כולו
			    else
				    table.insert(res, ones[digit1])
				end
			end
		end
	end
	
	if res[1] and math.floor(position / 3) == 0 then
		return res
	end	
	if math.floor(position / 3) == 1 and digit3 == 0 and ((digit1 ~= 0 and digit2 == 0) or  (digit1 == 0 and digit2 == 1)) then 
		table.insert(res,  thousands[digit1+digit2*10]) --טיפול מיוחד באלף עד עשרת אלפים
	else
		if digit1+digit2+digit3 > 0 then
		    table.insert(res, groups[math.floor(position / 3)]) -- אלף, מיליון וכך הלאה
		end
	end
	return res
end

local function _numeral_to_hebrew(mispar, gender, feature, termSingular, termPlural)
	local reversed = string.reverse(mispar) --היפוך המספר 
	local grouped, parts, ones = {}, {}, {}

--ones זיהוי ההמרה הנדרשת והעתקת הטבלה המתאימה להמרה זו לטבלה 
	if set('m', "masculine", 'ז', "זכר")[gender] then
		if set("cardinal", "מונה")[feature] then
			ones = m_cardinal
		elseif set("ordinal", "סודר", "סידורי")[feature] then
			if tonumber(mispar) < 11 then
				ones = m_ordinal
			else 
				ones = m_cardinal	
			end
		elseif set("construct", "נסמך")[feature] then
			ones = m_construct
		else
			ones = m_cardinal
		end
	elseif set('f', "feminine", 'נ', "נקבה")[gender] then
		if set("cardinal", "מונה")[feature] then
			ones = f_cardinal
		elseif set("ordinal", "סודר", "סידורי")[feature] then
			if tonumber(mispar) < 11 then
				ones = f_ordinal
			else 
				ones = f_cardinal	
			end
		elseif set("construct", "נסמך")[feature] then
			ones = f_construct
		else
			ones = f_cardinal
		end
	else --ברירת מחדל כשלא דווח מין
		if set("cardinal", "מונה")[feature] then
			ones = f_cardinal
		elseif set("ordinal", "סודר", "סידורי")[feature] then
			if tonumber(mispar) < 11 then
				ones = f_ordinal
			else 
				ones = f_cardinal	
			end
		elseif set("construct", "נסמך")[feature] then
			ones = f_construct
		else
			ones = f_cardinal
		end
	end
	
	if tonumber(mispar) == 0 then
		return ones[0]
	end

--המרת המספר למילים נעשית במנות של שלוש ספרות כל אחת.
--המנה הראשונה יכולה להיות גם של ספרה אחת או שתיים, תלוי באורך המספר	
	while reversed ~= '' do --הלולאה מסתיימת כאשר לא נותרו ספרות להמרה
		if math.fmod(#reversed, 3) ~= 0 then
			if math.fmod(#reversed, 3) == 2 then --במנה הראשונה יש רק שתי ספרות
				grouped = triadicGroup(	mispar, #reversed-1,
										0,
										tonumber(string.sub(reversed, #reversed, #reversed)) or 0,
										tonumber(string.sub(reversed, #reversed-1, #reversed-1)) or 0,
										ones
										)
			elseif math.fmod(#reversed, 3) == 1 then --במנה הראשונה יש רק ספרה אחת
				grouped = triadicGroup(	mispar, #reversed-1,
										0,
										0,
										tonumber(string.sub(reversed, #reversed, #reversed)) or 0,
										ones
										)
			end
			reversed = string.sub(reversed, 1, #reversed-math.fmod(#reversed, 3))--הסר את הספרות שטופלו
		else
			grouped = triadicGroup(	mispar, #reversed-1,
									tonumber(string.sub(reversed, #reversed, #reversed)) or 0,
									tonumber(string.sub(reversed, #reversed-1, #reversed-1)) or 0,
									tonumber(string.sub(reversed, #reversed-2, #reversed-2)) or 0,
									ones
									)
			reversed = string.sub(reversed, 1, #reversed-3)--הסר את שלוש הספרות שטופלו
		end
		tableConcat(parts, grouped)
		if math.floor(#reversed / 3) == 0 and math.fmod(#reversed, 3) == 0 then reversed = '' end
	end
	
	if termSingular ~= '' and termPlural ~= '' then
		if tonumber(mispar) == 1 then
			return termSingular..' '..stringify(parts)
		else
			return stringify(parts)..' '..termPlural
		end
	end
	return stringify(parts)
end

local p = {}

function p.numeral_to_hebrew(frame)
	local args = require('Module:Arguments').getArgs(frame)
	local mispar = args[1]
	local gender, feature, termSingular, termPlural
	local translatedArgs = {};
	for k,v in pairs(args) do
		if mw.ustring.match(k, '[א-ת]') ~=nil then
			local enKey = mw.ustring.gsub(k, 'מין', 'gender')
			enKey = mw.ustring.gsub(enKey, 'מגדר', 'gender')
			enKey = mw.ustring.gsub(enKey, 'תכונית', 'feature')
			enKey = mw.ustring.gsub(enKey, 'תכונה', 'feature')
			enKey = mw.ustring.gsub(enKey, 'סוג', 'feature')
			if k == 'יחידה' or k == 'רבות' then
				gender = "feminine"
			elseif k == 'יחיד' or k == 'רבים' then
				gender = "masculine"
			end
			enKey = mw.ustring.gsub(enKey, 'יחידה', 'singular')
			enKey = mw.ustring.gsub(enKey, 'יחיד', 'singular')
			enKey = mw.ustring.gsub(enKey, 'רבות', 'plural')
			enKey = mw.ustring.gsub(enKey, 'רבים', 'plural')

			translatedArgs[enKey] = v
		else
			translatedArgs[k] = v
		end
	end
	
	gender = gender or translatedArgs['gender']
	feature = translatedArgs['feature']
	termSingular = translatedArgs['singular']
	termPlural = translatedArgs['plural']
	
	if termSingular and termPlural then
		feature = 'construct'
	end
	
	return _numeral_to_hebrew(
		mispar,
		gender or '',
		feature or '',
		termSingular or '',
		termPlural or ''
	) or ''
end

return {
	['המר'] = p.numeral_to_hebrew,
	convert = p.numeral_to_hebrew
}