Module:ConvertNumeric
Itsura
This module is rated as ready for general use. It has reached a mature form and is thought to be bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
Ang Lua module na ito ay ginagamit ng nasa 26,000 pahina at posibleng mapapansin agad ang mga pagbabago. Pakisubok muna ang mga balak na pagbabago sa subpahina ng module na /burador o /pagsubok, o sa sarili mong module sandbox. Pag-usapan muna ang mga balak na pagbabago sa pahina ng usapan bago gawin ito. |
Usage
[baguhin ang wikitext]{{#invoke:ConvertNumeric|function_name}}
See also
[baguhin ang wikitext]- {{Spellnum per MOS}}
- {{Number to word}}
- Module:StripToNumbers - extract a number from a string (supports negatives and decimals) and return it, or optionally return a halved value
-- Module for converting between different representations of numbers. See talk page for user documentation.
-- For unit tests see: [[Module:ConvertNumeric/testcases]]
-- When editing, preview with: [[Module_talk:ConvertNumeric/testcases]]
-- First, edit [[Module:ConvertNumeric/sandbox]], then preview with [[Module_talk:ConvertNumeric/sandbox/testcases]]
local ones_position = {
[0] = 'sero',
[1] = 'isa',
[2] = 'dalawa',
[3] = 'tatlo',
[4] = 'apat',
[5] = 'lima',
[6] = 'anim',
[7] = 'pito',
[8] = 'walo',
[9] = 'siyam',
[10] = 'sampu',
[11] = 'labing-isa',
[12] = 'labindalawa',
[13] = 'labintatlo',
[14] = 'labing-apat',
[15] = 'labinlima',
[16] = 'labing-anim',
[17] = 'labimpito',
[18] = 'labing-walo',
[19] = 'labinsiyam'
}
local ones_position_ord = {
[0] = 'ikasero',
[1] = 'una',
[2] = 'ikalawa',
[3] = 'ikatlo',
[4] = 'ikaapat',
[5] = 'ikalima',
[6] = 'ikaanim',
[7] = 'ikapito',
[8] = 'ikawalo',
[9] = 'ikasiyam',
[10] = 'ikasampu',
[11] = 'ikalabing-isa',
[12] = 'ikalabindalawa',
[13] = 'ikalabintatlo',
[14] = 'ikalabing-apat',
[15] = 'ikalabinlima',
[16] = 'ikalabing-anim',
[17] = 'ikalabimpito',
[18] = 'ikalabing-walo',
[19] = 'ikalabinsiyam'
}
local ones_position_plural = {
[0] = 'zeros',
[1] = 'ones',
[2] = 'twos',
[3] = 'threes',
[4] = 'fours',
[5] = 'fives',
[6] = 'sixes',
[7] = 'sevens',
[8] = 'eights',
[9] = 'nines',
[10] = 'tens',
[11] = 'elevens',
[12] = 'twelves',
[13] = 'thirteens',
[14] = 'fourteens',
[15] = 'fifteens',
[16] = 'sixteens',
[17] = 'seventeens',
[18] = 'eighteens',
[19] = 'nineteens'
}
local tens_position = {
[2] = 'dalawampu',
[3] = 'tatlumpu',
[4] = 'apatnapu',
[5] = 'limampu',
[6] = 'animnapu',
[7] = 'pitumpu',
[8] = 'walumpu',
[9] = 'siyamnapu'
}
local tens_position_ord = {
[2] = 'ikadalawampu',
[3] = 'ikatatlumpu',
[4] = 'ikaapatnapu',
[5] = 'ikalimampu',
[6] = 'ikaanimnapu',
[7] = 'ikapitumpu',
[8] = 'ikawalumpu',
[9] = 'ikasiyamnapu'
}
local groups = {
[1] = 'libo',
[2] = 'milyon',
[3] = 'bilyon',
[4] = 'trilyon',
[5] = 'kuwadrilyon',
[6] = 'kintilyon',
[7] = 'sekstilyon',
[8] = 'septilyon',
[9] = 'oktilyon',
[10] = 'nonilyon',
[11] = 'desilyon',
[12] = 'undesilyon',
[13] = 'duwodesilyon',
[14] = 'tredesilyon',
[15] = 'kuwatuwordesilyon',
[16] = 'kuwindesilyon',
[17] = 'seksdesilyon',
[18] = 'septendesilyon',
[19] = 'oktodesilyon',
[20] = 'nobemdesilyon',
[21] = 'bigintilyon',
[22] = 'unbigintilyon',
[23] = 'duwobigintilyon',
[24] = 'tresbigintilyon',
[25] = 'kuwatuworbigintilyon',
[26] = 'kuwinkuwabigintilyon',
[27] = 'sesbigintilyon',
[28] = 'septembigintilyon',
[29] = 'oktobigintilyon',
[30] = 'nobembigintilyon',
[31] = 'trigintilyon',
[32] = 'untrigintilyon',
[33] = 'duwotrigintilyon',
[34] = 'trestrigintilyon',
[35] = 'kuwatuwortrigintilyon',
[36] = 'kuwinkuwatrigintilyon',
[37] = 'sestrigintilyon',
[38] = 'septentrigintilyon',
[39] = 'oktotrigintilyon',
[40] = 'nobentrigintilyon',
[41] = 'kuwadragintilyon',
[51] = 'kuwinkuwagintilyon',
[61] = 'seksagintilyon',
[71] = 'septuwagintilyon',
[81] = 'oktogintilyon',
[91] = 'nonagintilyon',
[101] = 'sentilyon',
[102] = 'unsentilyon',
[103] = 'duwosentilyon',
[104] = 'tresentilyon',
[111] = 'desisentilyon',
[112] = 'undesisentilyon',
[121] = 'bigintisentilyon',
[122] = 'unbigintisentilyon',
[131] = 'trigintasentilyon',
[141] = 'kuwadragintasentilyon',
[151] = 'kuwinkuwagintasentiyon',
[161] = 'seksagintasentilyon',
[171] = 'septuwagintasentilyon',
[181] = 'oktogintasentilyon',
[191] = 'nonagintasentilyon',
[201] = 'dusentilyon',
[301] = 'tresentilyon',
[401] = 'kuwadringentilyon',
[501] = 'kuwingentilyon',
[601] = 'sesentilyon',
[701] = 'septingentilyon',
[801] = 'oktingentilyon',
[901] = 'nongentilyon',
[1001] = 'millinilyon',
}
local roman_numerals = {
I = 1,
V = 5,
X = 10,
L = 50,
C = 100,
D = 500,
M = 1000
}
local tag_lt20 = {
['ikasero'] = 0,
['una'] = 1,
['ikalawa'] = 2,
['ikatlo'] = 3,
['ikaapat'] = 4,
['ikalima'] = 5,
['ikaanim'] = 6,
['ikapito'] = 7,
['ikawalo'] = 8,
['ikasiyam'] = 9,
['ikasampu'] = 10,
['ikalabing-isa'] = 11,
['ikalabindalawa'] = 12,
['ikalabintatlo'] = 13,
['ikalabing-apat'] = 14,
['ikalabinlima'] = 15,
['ikalabing-anim'] = 16,
['ikalabimpito'] = 17,
['ikalabing-walo'] = 18,
['ikalabinsiyam'] = 19,
}
local tag_tens_cont = {
['ikadalawampu'] = 20,
['ikatatlumpu'] = 30,
['ikaapatnapu'] = 40,
['ikalimampu'] = 50,
['ikanimnapu'] = 60,
['ikapitumpu'] = 70,
['ikawalumpu'] = 80,
['ikasiyamnapu'] = 90,
}
local tag_tens_cont = {
['dalawampu'] = 20,
['tatlumpu'] = 30,
['apatnapu'] = 40,
['limampu'] = 50,
['animnapu'] = 60,
['pitumpu'] = 70,
['walumpu'] = 80,
['siyamnapu'] = 90,
}
-- Converts a given valid roman numeral (and some invalid roman numerals) to a number. Returns -1, errorstring on error
local function roman_to_numeral(roman)
if type(roman) ~= "string" then return -1, "roman numeral not a string" end
local rev = roman:reverse()
local raising = true
local last = 0
local result = 0
for i = 1, #rev do
local c = rev:sub(i, i)
local next = roman_numerals[c]
if next == nil then return -1, "roman numeral contains illegal character " .. c end
if next > last then
result = result + next
raising = true
elseif next < last then
result = result - next
raising = false
elseif raising then
result = result + next
else
result = result - next
end
last = next
end
return result
end
-- Converts a given integer between 0 and 100 to Tagalog text (e.g. 47 -> forty-seven)
local function numeral_to_tagalog_less_100(num, ordinal, plural, zero)
local terminal_ones, terminal_tens, ika, mga
ika = ''
mga = ''
if ordinal then
if num < 20 then
terminal_ones = ones_position_ord
elseif num % 10 == 0 then
terminal_tens = tens_position_ord
else
terminal_ones = ones_position
terminal_tens = tens_position
ika = "ika"
end
elseif plural then
terminal_ones = ones_position
terminal_tens = tens_position
mga = ""
else
terminal_ones = ones_position
terminal_tens = tens_position
end
if num == 0 and zero ~= nil then
return zero
elseif num < 20 then
return terminal_ones[num]
elseif num % 10 == 0 then
return terminal_tens[num / 10]
else
return mga .. ika .. tens_position[math.floor(num / 10)] .. "'t" .. ' ' .. terminal_ones[num % 10]
end
end
local function standard_suffix(ordinal, plural)
if ordinal then return 'ika' end
if plural then return 'mga ' end
return ''
end
local function numeral_naong(num, bilang, st)
if bilang < 6 then
if (num == 4 or num == 6 or num == 9) then
return ' na'
else
return 'ng'
end
else
if (st == 'apat' or st == 'anim' or st == 'siyam') then
return ' na'
else
return 'ng'
end
end
end
local function text_naong(ch, bilang)
if (ch == 't' or ch == 'm') then
return ' na'
elseif ch == ' ' then
return ''
else
return 'ng'
end
end
local function daanoraan(num, bilang)
if bilang > 5 then
if (num == 4 or num == 6 or num == 9) then
return ' raang '
else
return ' daang '
end
else
if (num == 4 or num == 6 or num == 9) then
return ' raan '
else
return ' daan '
end
end
end
local function daatoraat(num)
if (num == 4 or num == 6 or num == 9) then
return " raa't "
else
return " daa't "
end
end
-- Converts a given integer (in string form) between 0 and 1000 to Tagalog text (e.g. 47 -> forty-seven)
local function numeral_to_tagalog_less_1000(num, use_and, ordinal, plural, zero, bilang)
num = tonumber(num)
if num < 100 then
return numeral_to_tagalog_less_100(num, ordinal, plural, zero)
elseif num % 100 == 0 then
return standard_suffix(ordinal, plural) .. ones_position[num/100] .. numeral_naong(num/100, bilang, ones_position[num/100]) .. daanoraan(num/100, bilang)
else
if ordinal then
return standard_suffix(ordinal, plural) .. ones_position[math.floor(num/100)] .. numeral_naong(math.floor(num/100), bilang, ones_position[math.floor(num/100)]) .. daatoraat(math.floor(num/100)) .. numeral_to_tagalog_less_100(num % 100, not ordinal, plural, zero)
else
return standard_suffix(ordinal, plural) .. ones_position[math.floor(num/100)] .. numeral_naong(math.floor(num/100), bilang, ones_position[math.floor(num/100)]) .. daatoraat(math.floor(num/100)) .. numeral_to_tagalog_less_100(num % 100, ordinal, plural, zero)
end
end
end
-- Converts an Tagalog-text ordinal between 'zeroth' and 'ninety-ninth' to a number [0–99], else -1
local function tagalog_to_ordinal(tagalog)
local tag = string.lower(tagalog or '')
local tag_lt20 = tag_lt20
local tag_tens_cont = tag_tens_cont
local tag_tens_cont = tag_tens_cont
if tag_lt20[tag] then
return tag_lt20[tag] --e.g. first -> 1
elseif tag_tens_cont[tag] then
return tag_tens_cont[tag] --e.g. ninetieth -> 90
else
local tens, ones = string.match(tag, '^([a-z]+)%-([a-z]+)$')
if tens and ones then
local tens_cont = tag_tens_cont[tens]
local ones_end = tag_lt20[ones]
if tens_cont and ones_end then
return tens_cont + ones_end --e.g. ninety-ninth -> 99
end
end
end
return -1 --failed
end
-- Converts a number expressed as a string in scientific notation to a string in standard decimal notation
-- e.g. 1.23E5 -> 123000, 1.23E-5 = .0000123. Conversion is exact, no rounding is performed.
local function scientific_notation_to_decimal(num)
local exponent, subs = num:gsub("^%-?%d*%.?%d*%-?[Ee]([+%-]?%d+)$", "%1")
if subs == 0 then return num end -- Input not in scientific notation, just return unmodified
exponent = tonumber(exponent)
local negative = num:find("^%-")
local _, decimal_pos = num:find("%.")
-- Mantissa will consist of all decimal digits with no decimal point
local mantissa = num:gsub("^%-?(%d*)%.?(%d*)%-?[Ee][+%-]?%d+$", "%1%2")
if negative and decimal_pos then decimal_pos = decimal_pos - 1 end
if not decimal_pos then decimal_pos = #mantissa + 1 end
-- Remove leading zeros unless decimal point is in first position
while decimal_pos > 1 and mantissa:sub(1,1) == '0' do
mantissa = mantissa:sub(2)
decimal_pos = decimal_pos - 1
end
-- Shift decimal point right for exponent > 0
while exponent > 0 do
decimal_pos = decimal_pos + 1
exponent = exponent - 1
if decimal_pos > #mantissa + 1 then mantissa = mantissa .. '0' end
-- Remove leading zeros unless decimal point is in first position
while decimal_pos > 1 and mantissa:sub(1,1) == '0' do
mantissa = mantissa:sub(2)
decimal_pos = decimal_pos - 1
end
end
-- Shift decimal point left for exponent < 0
while exponent < 0 do
if decimal_pos == 1 then
mantissa = '0' .. mantissa
else
decimal_pos = decimal_pos - 1
end
exponent = exponent + 1
end
-- Insert decimal point in correct position and return
return (negative and '-' or '') .. mantissa:sub(1, decimal_pos - 1) .. '.' .. mantissa:sub(decimal_pos)
end
-- Rounds a number to the nearest integer (NOT USED)
local function round_num(x)
if x%1 >= 0.5 then
return math.ceil(x)
else
return math.floor(x)
end
end
-- Rounds a number to the nearest two-word number (round = up, down, or "on" for round to nearest)
-- Numbers with two digits before the decimal will be rounded to an integer as specified by round.
-- Larger numbers will be rounded to a number with only one nonzero digit in front and all other digits zero.
-- Negative sign is preserved and does not count towards word limit.
local function round_for_tagalog(num, round)
-- If an integer with at most two digits, just return
if num:find("^%-?%d?%d%.?$") then return num end
local negative = num:find("^%-")
if negative then
-- We're rounding magnitude so flip it
if round == 'up' then round = 'down' elseif round == 'down' then round = 'up' end
end
-- If at most two digits before decimal, round to integer and return
local _, _, small_int, trailing_digits, round_digit = num:find("^%-?(%d?%d?)%.((%d)%d*)$")
if small_int then
if small_int == '' then small_int = '0' end
if (round == 'up' and trailing_digits:find('[1-9]')) or (round == 'on' and tonumber(round_digit) >= 5) then
small_int = tostring(tonumber(small_int) + 1)
end
return (negative and '-' or '') .. small_int
end
-- When rounding up, any number with > 1 nonzero digit will round up (e.g. 1000000.001 rounds up to 2000000)
local nonzero_digits = 0
for digit in num:gfind("[1-9]") do
nonzero_digits = nonzero_digits + 1
end
num = num:gsub("%.%d*$", "") -- Remove decimal part
-- Second digit used to determine which way to round lead digit
local _, _, lead_digit, round_digit, round_digit_2, rest = num:find("^%-?(%d)(%d)(%d)(%d*)$")
if tonumber(lead_digit .. round_digit) < 20 and (1 + #rest) % 3 == 0 then
-- In Tagalog numbers < 20 are one word so put 2 digits in lead and round based on 3rd
lead_digit = lead_digit .. round_digit
round_digit = round_digit_2
else
rest = round_digit_2 .. rest
end
if (round == 'up' and nonzero_digits > 1) or (round == 'on' and tonumber(round_digit) >= 5) then
lead_digit = tostring(tonumber(lead_digit) + 1)
end
-- All digits but lead digit will turn to zero
rest = rest:gsub("%d", "0")
return (negative and '-' or '') .. lead_digit .. '0' .. rest
end
local denominators = {
[2] = { 'kalahati', plural = 'mga kalahati' },
[3] = { 'isang-katlo' },
[4] = { 'sangkapat', us = 'pang-apat' },
[5] = { 'ikalimang bahagi' },
[6] = { 'ikaanim na bahagi' },
[8] = { 'ikawalong bahagi' },
[9] = { 'ikasiyam na bahagi' },
[10] = { 'ikasampu' },
[16] = { 'ikalabing-anim na bahagi' },
}
-- Return status, fraction where:
-- status is a string:
-- "finished" if there is a fraction with no whole number;
-- "ok" if fraction is empty or valid;
-- "unsupported" if bad fraction;
-- fraction is a string giving (numerator / denominator) as Tagalog text, or is "".
-- Only unsigned fractions with a very limited range of values are supported,
-- except that if whole is empty, the numerator can use "-" to indicate negative.
-- whole (string or nil): nil or "" if no number before the fraction
-- numerator (string or nil): numerator, if any (default = 1 if a denominator is given)
-- denominator (string or nil): denominator, if any
-- sp_us (boolean): true if sp=us
-- negative_word (string): word to use for negative sign, if whole is empty
-- use_one (boolean): false: 2+1/2 → "two and a half"; true: "two and one-half"
local function fraction_to_tagalog(whole, numerator, denominator, sp_us, negative_word, use_one)
if numerator or denominator then
local finished = (whole == nil or whole == '')
local sign = ''
if numerator then
if finished and numerator:sub(1, 1) == '-' then
numerator = numerator:sub(2)
sign = negative_word .. ' '
end
else
numerator = '1'
end
if not numerator:match('^%d+$') or not denominator or not denominator:match('^%d+$') then
return 'unsupported', ''
end
numerator = tonumber(numerator)
denominator = tonumber(denominator)
local dendata = denominators[denominator]
if not (dendata and 1 <= numerator and numerator <= 99) then
return 'unsupported', ''
end
local numstr, denstr
local sep = '-'
if numerator == 1 then
denstr = sp_us and dendata.us or dendata[1]
if finished or use_one then
numstr = 'isang'
elseif denstr:match('^[aeiou]') then
numstr = 'isang'
sep = ' '
else
numstr = 'isang'
sep = ' '
end
else
numstr = numeral_to_tagalog_less_100(numerator)
denstr = dendata.plural
if not denstr then
denstr = (sp_us and dendata.us or dendata[1]) .. 's'
end
end
if finished then
return 'finished', sign .. numstr .. sep .. denstr
end
return 'ok', ' and ' .. numstr .. sep .. denstr
end
return 'ok', ''
end
-- Takes a decimal number and converts it to Tagalog text.
-- Return nil if a fraction cannot be converted (only some numbers are supported for fractions).
-- num (string or nil): the number to convert.
-- Can be an arbitrarily large decimal, such as "-123456789123456789.345", and
-- can use scientific notation (e.g. "1.23E5").
-- May fail for very large numbers not listed in "groups" such as "1E4000".
-- num is nil if there is no whole number before a fraction.
-- numerator (string or nil): numerator of fraction (nil if no fraction)
-- denominator (string or nil): denominator of fraction (nil if no fraction)
-- capitalize (boolean): whether to capitalize the result (e.g. 'One' instead of 'one')
-- use_and (boolean): whether to use the word 'and' between tens/ones place and higher places
-- hyphenate (boolean): whether to hyphenate all words in the result, useful for use as an adjective
-- ordinal (boolean): whether to produce an ordinal (e.g. 'first' instead of 'one')
-- plural (boolean): whether to pluralize the resulting number
-- links: nil: do not add any links; 'on': link "billion" and larger to Orders of magnitude article;
-- any other text: list of numbers to link (e.g. "billion,quadrillion")
-- negative_word: word to use for negative sign (typically 'negative' or 'minus'; nil to use default)
-- round: nil or '': no rounding; 'on': round to nearest two-word number; 'up'/'down': round up/down to two-word number
-- zero: word to use for value '0' (nil to use default)
-- use_one (boolean): false: 2+1/2 → "two and a half"; true: "two and one-half"
local function _numeral_to_tagalog(num, numerator, denominator, capitalize, use_and, hyphenate, ordinal, plural, links, negative_word, round, zero, use_one)
if not negative_word then
if use_and then
-- TODO Should 'minus' be used when do not have sp=us?
-- If so, need to update testcases, and need to fix "minus zero".
-- negative_word = 'minus'
negative_word = 'negatibo'
else
negative_word = 'negatibo'
end
end
local status, fraction_text = fraction_to_tagalog(num, numerator, denominator, not use_and, negative_word, use_one)
if status == 'unsupported' then
return nil
end
if status == 'finished' then
-- Input is a fraction with no whole number.
-- Hack to avoid executing stuff that depends on num being a number.
local s = fraction_text
if hyphenate then s = s:gsub("%s", "-") end
if capitalize then s = s:gsub("^%l", string.upper) end
return s
end
num = scientific_notation_to_decimal(num)
if round and round ~= '' then
if round ~= 'on' and round ~= 'up' and round ~= 'down' then
error("Invalid rounding mode")
end
num = round_for_tagalog(num, round)
end
-- Separate into negative sign, num (digits before decimal), decimal_places (digits after decimal)
local MINUS = '−' -- Unicode U+2212 MINUS SIGN (may be in values from [[Module:Convert]])
if num:sub(1, #MINUS) == MINUS then
num = '-' .. num:sub(#MINUS + 1) -- replace MINUS with '-'
elseif num:sub(1, 1) == '+' then
num = num:sub(2) -- ignore any '+'
end
local negative = num:find("^%-")
local decimal_places, subs = num:gsub("^%-?%d*%.(%d+)$", "%1")
if subs == 0 then decimal_places = nil end
num, subs = num:gsub("^%-?(%d*)%.?%d*$", "%1")
if num == '' and decimal_places then num = '0' end
if subs == 0 or num == '' then error("Invalid decimal numeral") end
-- For each group of 3 digits except the last one, print with appropriate group name (e.g. million)
local s = ''
if (ordinal or plural) and #num > 3 then
-- Round numbers like "one million" take standard suffixes for ordinal/plural
s = s .. standard_suffix(ordinal, plural)
end
local bilang = #num
while #num > 3 do
if (s ~= '' and s ~= 'ika') then
s = s .. ' '
end
local group_num = math.floor((#num - 1) / 3)
local group = groups[group_num]
local group_digits = #num - group_num*3
local numtag
if ordinal then
numtag = numeral_to_tagalog_less_1000(num:sub(1, group_digits), use_and, not ordinal, plural, zero, bilang)
else
numtag = numeral_to_tagalog_less_1000(num:sub(1, group_digits), use_and, ordinal, plural, zero, bilang)
end
s = s .. numtag .. text_naong(numtag:sub(numtag:len(numtag)), bilang) .. ' '
-- if links and (((links == 'on' and group_num >= 3) or links:find(group)) and group_num <= 13) then
-- s = s .. '[[Orders_of_magnitude_(numbers)#10' .. group_num*3 .. '|' .. group .. ']]'
-- else
if group == 'libo' and num:sub(num:len(num) - 3) % 1000 == 0 then
s = s .. group
elseif group == 'libo' and num:sub(num:len(num) - 3) % 1000 ~= 0 then
s = s .. "libo't"
else
s = s .. group
end
-- end
num = num:sub(1 + group_digits)
num = num:gsub("^0*", "") -- Trim leading zeros
end
-- Handle final three digits of integer part
if s ~= '' and num ~= '' then
if #num <= 2 and use_and then
s = s .. ' at '
else
s = s .. ' '
end
end
local c1, c2
if s == '' or num ~= '' then
if (ordinal and bilang > 3) then
c2 = numeral_to_tagalog_less_1000(num, use_and, ordinal, plural, zero, bilang)
if c2 == 'una' then
c1 = 'isa'
elseif c2 == 'ikalawa' then
c1 = 'dalawa'
elseif c2 == 'ikatlo' then
c1 = 'tatlo'
else
c1 = numeral_to_tagalog_less_1000(num, use_and, ordinal, plural, zero, bilang):sub(4)
end
s = s .. c1
else
s = s .. numeral_to_tagalog_less_1000(num, use_and, ordinal, plural, zero, bilang)
end
end
-- For decimal places (if any) output "point" followed by spelling out digit by digit
if decimal_places then
s = s .. ' point'
for i = 1, #decimal_places do
s = s .. ' ' .. ones_position[tonumber(decimal_places:sub(i,i))]
end
end
s = s:gsub("^%s*(.-)%s*$", "%1") -- Trim whitespace
if ordinal and plural then s = s .. 's' end -- s suffix works for all ordinals
if negative and s ~= zero then s = negative_word .. ' ' .. s end
s = s:gsub("negative zero", "zero")
s = s .. fraction_text
if hyphenate then s = s:gsub("%s", "-") end
if capitalize then s = s:gsub("^%l", string.upper) end
return s
end
local function _numeral_to_tagalog2(args)
local num = args.num
if (not tonumber(num)) then
num = num:gsub("^%s*(.-)%s*$", "%1") -- Trim whitespace
num = num:gsub(",", "") -- Remove commas
num = num:gsub("^<span[^<>]*></span>", "") -- Generated by Template:age
if num ~= '' then -- a fraction may have an empty whole number
if not num:find("^%-?%d*%.?%d*%-?[Ee]?[+%-]?%d*$") then
-- Input not in a valid format, try to pass it through #expr to see
-- if that produces a number (e.g. "3 + 5" will become "8").
num = mw.getCurrentFrame():preprocess('{{#expr: ' .. num .. '}}')
end
end
end
-- Pass args from frame to helper function
return _numeral_to_tagalog(
num,
args['numerator'],
args['denominator'],
args['capitalize'],
args['use_and'],
args['hyphenate'],
args['ordinal'],
args['plural'],
args['links'],
args['negative_word'],
args['round'],
args['zero'],
args['use_one']
) or ''
end
local p = { -- Functions that can be called from another module
roman_to_numeral = roman_to_numeral,
spell_number = _numeral_to_tagalog,
spell_number2 = _numeral_to_tagalog2,
tagalog_to_ordinal = tagalog_to_ordinal,
}
function p._roman_to_numeral(frame) -- Callable via {{#invoke:ConvertNumeric|_roman_to_numeral|VI}}
return roman_to_numeral(frame.args[1])
end
function p._tagalog_to_ordinal(frame) -- callable via {{#invoke:ConvertNumeric|_tagalog_to_ordinal|First}}
return tagalog_to_ordinal(frame.args[1])
end
function p.numeral_to_tagalog(frame)
local args = frame.args
local num = args[1]
num = num:gsub("^%s*(.-)%s*$", "%1") -- Trim whitespace
num = num:gsub(",", "") -- Remove commas
num = num:gsub("^<span[^<>]*></span>", "") -- Generated by Template:age
if num ~= '' then -- a fraction may have an empty whole number
if not num:find("^%-?%d*%.?%d*%-?[Ee]?[+%-]?%d*$") then
-- Input not in a valid format, try to pass it through #expr to see
-- if that produces a number (e.g. "3 + 5" will become "8").
num = frame:preprocess('{{#expr: ' .. num .. '}}')
end
end
-- Pass args from frame to helper function
return _numeral_to_tagalog(
num,
args['numerator'],
args['denominator'],
args['case'] == 'U' or args['case'] == 'u',
args['sp'] ~= 'us',
args['adj'] == 'on',
args['ord'] == 'on',
args['pl'] == 'on',
args['lk'],
args['negative'],
args['round'],
args['zero'],
args['one'] == 'one' -- experiment: using '|one=one' makes fraction 2+1/2 give "two and one-half" instead of "two and a half"
) or ''
end
---- recursive function for p.decToHex
local function decToHexDigit(dec)
local dig = {"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}
local div = math.floor(dec/16)
local mod = dec-(16*div)
if div >= 1 then return decToHexDigit(div)..dig[mod+1] else return dig[mod+1] end
end -- I think this is supposed to be done with a tail call but first I want something that works at all
---- finds all the decimal numbers in the input text and hexes each of them
function p.decToHex(frame)
local args=frame.args
local parent=frame.getParent(frame)
local pargs={}
if parent then pargs=parent.args end
local text=args[1] or pargs[1] or ""
local minlength=args.minlength or pargs.minlength or 1
minlength=tonumber(minlength)
local prowl=mw.ustring.gmatch(text,"(.-)(%d+)")
local output=""
repeat
local chaff,dec=prowl()
if not(dec) then break end
local hex=decToHexDigit(dec)
while (mw.ustring.len(hex)<minlength) do hex="0"..hex end
output=output..chaff..hex
until false
local chaff=mw.ustring.match(text,"(%D+)$") or ""
return output..chaff
end
return p