Module:ConvertNumeric
- Afrikaans
- Аԥсшәа
- العربية
- অসমীয়া
- Авар
- تۆرکجه
- Basa Bali
- বাংলা
- 閩南語 / Bân-lâm-gí
- Беларуская (тарашкевіца)
- भोजपुरी
- Bikol Central
- Български
- Bosanski
- Буряад
- Català
- Chavacano de Zamboanga
- Dansk
- الدارجة
- Eesti
- Ελληνικά
- Español
- فارسی
- Føroyskt
- Français
- Gaelg
- ગુજરાતી
- 한국어
- Hausa
- Հայերեն
- हिन्दी
- Ilokano
- Bahasa Indonesia
- Íslenska
- עברית
- ಕನ್ನಡ
- Kurdî
- ລາວ
- Latina
- Latviešu
- Lietuvių
- Magyar
- Македонски
- മലയാളം
- Malti
- Bahasa Melayu
- Мокшень
- Монгол
- မြန်မာဘာသာ
- Nederlands
- नेपाली
- 日本語
- Нохчийн
- Norsk bokmål
- ଓଡ଼ିଆ
- Oʻzbekcha / ўзбекча
- ਪੰਜਾਬੀ
- Papiamentu
- پښتو
- Português
- Română
- Русский
- ᱥᱟᱱᱛᱟᱲᱤ
- Scots
- Shqip
- සිංහල
- Simple English
- سنڌي
- Slovenčina
- Slovenščina
- کوردی
- Српски / srpski
- Srpskohrvatski / српскохрватски
- Suomi
- Svenska
- Tagalog
- தமிழ்
- တႆး
- తెలుగు
- ไทย
- Тоҷикӣ
- Türkçe
- Українська
- اردو
- Tiếng Việt
- 中文
- ⵜⴰⵎⴰⵣⵉⵖⵜ ⵜⴰⵏⴰⵡⴰⵢⵜ
Appearance
From Wikipedia, the free encyclopedia
Warning This Lua module is used on approximately 19,000 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them.
[画像:Warning] This Lua module is used in MediaWiki:Watchlist-messages , and on approximately 19,000 pages.
Changes to it can cause immediate changes to the Wikipedia user interface.
To avoid major disruption, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Please discuss changes on the talk page before implementing them.
Changes to it can cause immediate changes to the Wikipedia user interface.
To avoid major disruption, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Please discuss changes on the talk page before implementing them.
Usage
{{#invoke:ConvertNumeric|function_name}}
See also
- {{Spellnum per MOS }}
- {{Number to word }}
- Module:Strip to numbers – extract a number from a string (supports negatives and decimals) and return it, or optionally return a halved value
The above documentation is transcluded from Module:ConvertNumeric/doc. (edit | history)
Editors can experiment in this module's sandbox (edit | diff) and testcases (edit | run) pages.
Subpages of this module.
Editors can experiment in this module's sandbox (edit | diff) and testcases (edit | run) pages.
Subpages of this module.
-- 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]] require('strict') localones_position={ [0]='zero', [1]='one', [2]='two', [3]='three', [4]='four', [5]='five', [6]='six', [7]='seven', [8]='eight', [9]='nine', [10]='ten', [11]='eleven', [12]='twelve', [13]='thirteen', [14]='fourteen', [15]='fifteen', [16]='sixteen', [17]='seventeen', [18]='eighteen', [19]='nineteen' } localones_position_ord={ [0]='zeroth', [1]='first', [2]='second', [3]='third', [4]='fourth', [5]='fifth', [6]='sixth', [7]='seventh', [8]='eighth', [9]='ninth', [10]='tenth', [11]='eleventh', [12]='twelfth', [13]='thirteenth', [14]='fourteenth', [15]='fifteenth', [16]='sixteenth', [17]='seventeenth', [18]='eighteenth', [19]='nineteenth' } localones_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' } localtens_position={ [2]='twenty', [3]='thirty', [4]='forty', [5]='fifty', [6]='sixty', [7]='seventy', [8]='eighty', [9]='ninety' } localtens_position_ord={ [2]='twentieth', [3]='thirtieth', [4]='fortieth', [5]='fiftieth', [6]='sixtieth', [7]='seventieth', [8]='eightieth', [9]='ninetieth' } localtens_position_plural={ [2]='twenties', [3]='thirties', [4]='forties', [5]='fifties', [6]='sixties', [7]='seventies', [8]='eighties', [9]='nineties' } localgroups={ [1]='thousand', [2]='million', [3]='billion', [4]='trillion', [5]='quadrillion', [6]='quintillion', [7]='sextillion', [8]='septillion', [9]='octillion', [10]='nonillion', [11]='decillion', [12]='undecillion', [13]='duodecillion', [14]='tredecillion', [15]='quattuordecillion', [16]='quindecillion', [17]='sexdecillion', [18]='septendecillion', [19]='octodecillion', [20]='novemdecillion', [21]='vigintillion', [22]='unvigintillion', [23]='duovigintillion', [24]='tresvigintillion', [25]='quattuorvigintillion', [26]='quinquavigintillion', [27]='sesvigintillion', [28]='septemvigintillion', [29]='octovigintillion', [30]='novemvigintillion', [31]='trigintillion', [32]='untrigintillion', [33]='duotrigintillion', [34]='trestrigintillion', [35]='quattuortrigintillion', [36]='quinquatrigintillion', [37]='sestrigintillion', [38]='septentrigintillion', [39]='octotrigintillion', [40]='noventrigintillion', [41]='quadragintillion', [51]='quinquagintillion', [61]='sexagintillion', [71]='septuagintillion', [81]='octogintillion', [91]='nonagintillion', [101]='centillion', [102]='uncentillion', [103]='duocentillion', [104]='trescentillion', [111]='decicentillion', [112]='undecicentillion', [121]='viginticentillion', [122]='unviginticentillion', [131]='trigintacentillion', [141]='quadragintacentillion', [151]='quinquagintacentillion', [161]='sexagintacentillion', [171]='septuagintacentillion', [181]='octogintacentillion', [191]='nonagintacentillion', [201]='ducentillion', [301]='trecentillion', [401]='quadringentillion', [501]='quingentillion', [601]='sescentillion', [701]='septingentillion', [801]='octingentillion', [901]='nongentillion', [1001]='millinillion', } localroman_numerals={ I=1, V=5, X=10, L=50, C=100, D=500, M=1000 } localengord_tens_end={ ['twentieth']=20, ['thirtieth']=30, ['fortieth']=40, ['fiftieth']=50, ['sixtieth']=60, ['seventieth']=70, ['eightieth']=80, ['ninetieth']=90, } localeng_tens_cont={ ['twenty']=20, ['thirty']=30, ['forty']=40, ['fifty']=50, ['sixty']=60, ['seventy']=70, ['eighty']=80, ['ninety']=90, } -- Converts a given valid roman numeral (and some invalid roman numerals) to a number. Returns { -1, errorstring } on error. localfunctionroman_to_numeral(roman) iftype(roman)~="string"thenreturn-1,"roman numeral not a string"end localrev=roman:reverse() localraising=true locallast=0 localresult=0 fori=1,#revdo localc=rev:sub(i,i) localnext=roman_numerals[c] ifnext==nilthenreturn-1,"roman numeral contains illegal character "..cend ifnext>lastthen result=result+next raising=true elseifnext<lastthen result=result-next raising=false elseifraisingthen result=result+next else result=result-next end last=next end returnresult end -- Converts a given integer between 0 and 100 to English text (e.g. 47 -> forty-seven). localfunctionnumeral_to_english_less_100(num,ordinal,plural,zero) localterminal_ones,terminal_tens ifordinalthen terminal_ones=ones_position_ord terminal_tens=tens_position_ord elseifpluralthen terminal_ones=ones_position_plural terminal_tens=tens_position_plural else terminal_ones=ones_position terminal_tens=tens_position end ifnum==0andzero~=nilthen returnzero elseifnum<20then returnterminal_ones[num] elseifnum%10==0then returnterminal_tens[num/10] else returntens_position[math.floor(num/10)]..'-'..terminal_ones[num%10] end end localfunctionstandard_suffix(ordinal,plural) ifordinalthenreturn'th'end ifpluralthenreturn's'end return'' end -- Converts a given integer (in string form) between 0 and 1000 to English text (e.g. 47 -> forty-seven). localfunctionnumeral_to_english_less_1000(num,use_and,ordinal,plural,zero) num=tonumber(num) ifnum<100then returnnumeral_to_english_less_100(num,ordinal,plural,zero) elseifnum%100==0then returnones_position[num/100]..' hundred'..standard_suffix(ordinal,plural) else returnones_position[math.floor(num/100)]..' hundred '..(use_andand'and 'or'')..numeral_to_english_less_100(num%100,ordinal,plural,zero) end end -- Converts an ordinal in English text from 'zeroth' to 'ninety-ninth' inclusive to a number [0–99], else -1. localfunctionenglish_to_ordinal(english) localeng=string.lower(englishor'') localengord_lt20={}-- ones_position_ord{} keys & values swapped fork,vinpairs(ones_position_ord)do engord_lt20[v]=k end ifengord_lt20[eng]then returnengord_lt20[eng]-- e.g. first -> 1 elseifengord_tens_end[eng]then returnengord_tens_end[eng]-- e.g. ninetieth -> 90 else localtens,ones=string.match(eng,'^([a-z]+)[%s%-]+([a-z]+)$') iftensandonesthen localtens_cont=eng_tens_cont[tens] localones_end=engord_lt20[ones] iftens_contandones_endthen returntens_cont+ones_end-- e.g. ninety-ninth -> 99 end end end return-1-- Failed end -- Converts a number in English text from 'zero' to 'ninety-nine' inclusive to a number [0–99], else -1. localfunctionenglish_to_numeral(english) localeng=string.lower(englishor'') localeng_lt20={['single']=1}-- ones_position{} keys & values swapped fork,vinpairs(ones_position)do eng_lt20[v]=k end ifeng_lt20[eng]then returneng_lt20[eng]-- e.g. one -> 1 elseifeng_tens_cont[eng]then returneng_tens_cont[eng]-- e.g. ninety -> 90 else localtens,ones=string.match(eng,'^([a-z]+)[%s%-]+([a-z]+)$') iftensandonesthen localtens_cont=eng_tens_cont[tens] localones_end=eng_lt20[ones] iftens_contandones_endthen returntens_cont+ones_end-- e.g. ninety-nine -> 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. localfunctionscientific_notation_to_decimal(num) localexponent,subs=num:gsub("^%-?%d*%.?%d*%-?[Ee]([+%-]?%d+)$","%1") ifsubs==0thenreturnnumend-- Input not in scientific notation, just return unmodified exponent=tonumber(exponent) localnegative=num:find("^%-") local_,decimal_pos=num:find("%.") -- Mantissa will consist of all decimal digits with no decimal point localmantissa=num:gsub("^%-?(%d*)%.?(%d*)%-?[Ee][+%-]?%d+$","%1%2") ifnegativeanddecimal_posthendecimal_pos=decimal_pos-1end ifnotdecimal_posthendecimal_pos=#mantissa+1end -- Remove leading zeros unless decimal point is in first position whiledecimal_pos>1andmantissa:sub(1,1)=='0'do mantissa=mantissa:sub(2) decimal_pos=decimal_pos-1 end -- Shift decimal point right for exponent > 0 whileexponent>0do decimal_pos=decimal_pos+1 exponent=exponent-1 ifdecimal_pos>#mantissa+1thenmantissa=mantissa..'0'end -- Remove leading zeros unless decimal point is in first position whiledecimal_pos>1andmantissa:sub(1,1)=='0'do mantissa=mantissa:sub(2) decimal_pos=decimal_pos-1 end end -- Shift decimal point left for exponent < 0 whileexponent<0do ifdecimal_pos==1then mantissa='0'..mantissa else decimal_pos=decimal_pos-1 end exponent=exponent+1 end -- Insert decimal point in correct position and return return(negativeand'-'or'')..mantissa:sub(1,decimal_pos-1)..'.'..mantissa:sub(decimal_pos) end -- Rounds a number to the nearest integer (NOT USED) localfunctionround_num(x) ifx%1>=0.5then returnmath.ceil(x) else returnmath.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. localfunctionround_for_english(num,round) -- If an integer with at most two digits, just return ifnum:find("^%-?%d?%d%.?$")thenreturnnumend localnegative=num:find("^%-") ifnegativethen -- We're rounding magnitude so flip it ifround=='up'thenround='down'elseifround=='down'thenround='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*)$") ifsmall_intthen ifsmall_int==''thensmall_int='0'end if(round=='up'andtrailing_digits:find('[1-9]'))or(round=='on'andtonumber(round_digit)>=5)then small_int=tostring(tonumber(small_int)+1) end return(negativeand'-'or'')..small_int end -- When rounding up, any number with > 1 nonzero digit will round up (e.g. 1000000.001 rounds up to 2000000) localnonzero_digits=0 fordigitinnum: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*)$") iftonumber(lead_digit..round_digit)<20and(1+#rest)%3==0then -- In English 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'andnonzero_digits>1)or(round=='on'andtonumber(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(negativeand'-'or'')..lead_digit..'0'..rest end localdenominators={ [2]={'half',plural='halves'}, [3]={'third'}, [4]={'quarter',us='fourth'}, [5]={'fifth'}, [6]={'sixth'}, [8]={'eighth'}, [9]={'ninth'}, [10]={'tenth'}, [16]={'sixteenth'}, } -- 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 English 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" localfunctionfraction_to_english(whole,numerator,denominator,sp_us,negative_word,use_one) ifnumeratorordenominatorthen localfinished=(whole==nilorwhole=='') localsign='' ifnumeratorthen iffinishedandnumerator:sub(1,1)=='-'then numerator=numerator:sub(2) sign=negative_word..' ' end else numerator='1' end ifnotnumerator:match('^%d+$')ornotdenominatorornotdenominator:match('^%d+$')then return'unsupported','' end numerator=tonumber(numerator) denominator=tonumber(denominator) localdendata=denominators[denominator] ifnot(dendataand1<=numeratorandnumerator<=99)then return'unsupported','' end localnumstr,denstr localsep='-' ifnumerator==1then denstr=sp_usanddendata.usordendata[1] iffinishedoruse_onethen numstr='one' elseifdenstr:match('^[aeiou]')then numstr='an' sep=' ' else numstr='a' sep=' ' end else numstr=numeral_to_english_less_100(numerator) denstr=dendata.plural ifnotdenstrthen denstr=(sp_usanddendata.usordendata[1])..'s' end end iffinishedthen 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 English 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 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" localfunction_numeral_to_english(num,numerator,denominator,capitalize,use_and,hyphenate,ordinal,plural,links,negative_word,round,zero,use_one) ifnotnegative_wordthen ifuse_andthen -- 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='negative' else negative_word='negative' end end localstatus,fraction_text=fraction_to_english(num,numerator,denominator,notuse_and,negative_word,use_one) ifstatus=='unsupported'then returnnil end ifstatus=='finished'then -- Input is a fraction with no whole number. -- Hack to avoid executing stuff that depends on num being a number. locals=fraction_text ifhyphenatethens=s:gsub("%s","-")end ifcapitalizethens=s:gsub("^%l",string.upper)end returns end num=scientific_notation_to_decimal(num) ifroundandround~=''then ifround~='on'andround~='up'andround~='down'then error("Invalid rounding mode") end num=round_for_english(num,round) end -- Separate into negative sign, num (digits before decimal), decimal_places (digits after decimal) localMINUS='−'-- Unicode U+2212 MINUS SIGN (may be in values from [[Module:Convert]]) ifnum:sub(1,#MINUS)==MINUSthen num='-'..num:sub(#MINUS+1)-- replace MINUS with '-' elseifnum:sub(1,1)=='+'then num=num:sub(2)-- ignore any '+' end localnegative=num:find("^%-") localdecimal_places,subs=num:gsub("^%-?%d*%.(%d+)$","%1") ifsubs==0thendecimal_places=nilend num,subs=num:gsub("^%-?(%d*)%.?%d*$","%1") ifnum==''anddecimal_placesthennum='0'end ifsubs==0ornum==''thenerror("Invalid decimal numeral")end -- For each group of 3 digits except the last one, print with appropriate group name (e.g. million) locals='' while#num>3do ifs~=''thens=s..' 'end localgroup_num=math.floor((#num-1)/3) localgroup=groups[group_num] localgroup_digits=#num-group_num*3 s=s..numeral_to_english_less_1000(num:sub(1,group_digits),false,false,false,zero)..' ' iflinksand(((links=='on'andgroup_num>=3)orlinks:find(group))andgroup_num<=13)then s=s..'[[Orders_of_magnitude_(numbers)#10'..group_num*3..'|'..group..']]' else s=s..group end num=num:sub(1+group_digits) num=num:gsub("^0*","")-- Trim leading zeros end -- Handle final three digits of integer part ifs~=''andnum~=''then if#num<=2anduse_andthen s=s..' and ' else s=s..' ' end end ifs==''ornum~=''then s=s..numeral_to_english_less_1000(num,use_and,ordinal,plural,zero) elseifordinalorpluralthen -- Round numbers like "one million" take standard suffixes for ordinal/plural s=s..standard_suffix(ordinal,plural) end -- For decimal places (if any) output "point" followed by spelling out digit by digit ifdecimal_placesthen s=s..' point' fori=1,#decimal_placesdo s=s..' '..ones_position[tonumber(decimal_places:sub(i,i))] end end s=s:gsub("^%s*(.-)%s*$","%1")-- Trim whitespace ifordinalandpluralthens=s..'s'end-- s suffix works for all ordinals ifnegativeands~=zerothens=negative_word..' '..send s=s:gsub("negative zero","zero") s=s..fraction_text ifhyphenatethens=s:gsub("%s","-")end ifcapitalizethens=s:gsub("^%l",string.upper)end returns end localfunction_numeral_to_english2(args) localnum=tostring(args.num) num=num:gsub("^%s*(.-)%s*$","%1")-- Trim whitespace num=num:gsub(",","")-- Remove commas num=num:gsub("^<span[^<>]*></span>","")-- Generated by Template:age ifnum~=''then-- a fraction may have an empty whole number ifnotnum:find("^%-?%d*%.?%d*%-?[Ee]?[+%-]?%d*$")then -- Input not in a valid format, try to eval it as an expr to see -- if that produces a number (e.g. "3 + 5" will become "8"). localnoerr,result=pcall(mw.ext.ParserFunctions.expr,num) ifnoerrthen num=result end end end -- Call helper function passing args return_numeral_to_english( 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 localp={-- Functions that can be called from another module roman_to_numeral=roman_to_numeral, spell_number=_numeral_to_english, spell_number2=_numeral_to_english2, english_to_ordinal=english_to_ordinal, english_to_numeral=english_to_numeral, } functionp._roman_to_numeral(frame)-- Callable via {{#invoke:ConvertNumeric|_roman_to_numeral|VI}} returnroman_to_numeral(frame.args[1]) end functionp._english_to_ordinal(frame)-- callable via {{#invoke:ConvertNumeric|_english_to_ordinal|First}} returnenglish_to_ordinal(frame.args[1]) end functionp._english_to_numeral(frame)-- callable via {{#invoke:ConvertNumeric|_english_to_numeral|One}} returnenglish_to_numeral(frame.args[1]) end functionp.numeral_to_english(frame) localargs=frame.args -- Tail call to helper function passing args from frame return_numeral_to_english2{ ['num']=args[1], ['numerator']=args['numerator'], ['denominator']=args['denominator'], ['capitalize']=args['case']=='U'orargs['case']=='u', ['use_and']=args['sp']~='us', ['hyphenate']=args['adj']=='on', ['ordinal']=args['ord']=='on', ['plural']=args['pl']=='on', ['links']=args['lk'], ['negative_word']=args['negative'], ['round']=args['round'], ['zero']=args['zero'], ['use_one']=args['one']=='one'-- experiment: using '|one=one' makes fraction 2+1/2 give "two and one-half" instead of "two and a half" } end ---- recursive function for p.decToHex localfunctiondecToHexDigit(dec) localdig={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"} localdiv=math.floor(dec/16) localmod=dec-(16*div) ifdiv>=1thenreturndecToHexDigit(div)..dig[mod+1]elsereturndig[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 functionp.decToHex(frame) localargs=frame.args localparent=frame.getParent(frame) localpargs={} ifparentthenpargs=parent.argsend localtext=args[1]orpargs[1]or"" localminlength=args.minlengthorpargs.minlengthor1 minlength=tonumber(minlength) localprowl=mw.ustring.gmatch(text,"(.-)(%d+)") localoutput="" repeat localchaff,dec=prowl() ifnot(dec)thenbreakend localhex=decToHexDigit(dec) while(mw.ustring.len(hex)<minlength)dohex="0"..hexend output=output..chaff..hex untilfalse localchaff=mw.ustring.match(text,"(%D+)$")or"" returnoutput..chaff end returnp