代码高尔夫:数字到单词

代码高尔夫系列似乎相当受欢迎。 我遇到了一些代码,将数字转换为单词表示。 一些例子是(编程乐趣2的幂):

  • 2 – >二
  • 1024 – >一二四
  • 1048576 – >一百四十八万五千七十六

我的同事提出的algorithm差不多是二百行。 似乎有一个更简洁的方法来做到这一点。

目前的准则:

  • 用任何编程语言提交的意见都表示欢迎(对于PhiLho最初缺乏清晰度,我向他们道歉)
  • 最大input2 ^ 64(请参阅以下链接,谢谢mmeyers)
  • 英文输出的规模较小,但任何algorithm是受欢迎的。 只是就使用的方法评论编程语言。

Lisp,只使用标准函数:

(format nil "~r" 1234) ==> "one thousand two hundred thirty-four" 

奖金:

 (format nil "~@r" 1234) ==> "MCCXXXIV" 

好吧,我认为是在Windows BATCH脚本中自己实现的时候了(应该可以在Windows 2000或更高版本上运行)。

这里是代码:

 @echo off set zero_to_nineteen=Zero One Two Three Four Five Six Seven Eight Nine Ten Eleven Twelve Thirteen Fourteen Fifteen Sixteen Seventeen Eighteen Nineteen set twenty_to_ninety=ignore ignore Twenty Thirty Forty Fifty Sixty Seventy Eighty Ninety set big_numbers=ignore Thousand Million Billion Trillion Quadrillion Quintillion Sextillion Septillion Octillion Nonillion Decillion Undecillion Duodecillion Tredecillion Quattuordecillion Quindecillion Sexdecillion Septendecillion Octodecillion Novemdecillion Vigintillion rem 10^0 10^3 10^6 10^9 10^12 10^15 10^18 10^21 10^24 10^27 10^30 10^33 10^36 10^39 10^42 10^45 10^48 10^51 10^54 10^57 10^60 10^63 call :parse_numbers %* exit /B 0 :parse_numbers :parse_numbers_loop if "$%~1" == "$" goto parse_numbers_end call :parse_number %~1 echo %~1 -^> %parse_number_result% shift goto parse_numbers_loop :parse_numbers_end exit /B 0 :parse_number call :get_sign %~1 set number_sign=%get_sign_result% call :remove_groups %get_sign_result_number% call :trim_leading_zeros %remove_groups_result% set number=%trim_leading_zeros_result% if "$%number%" == "$0" ( set parse_number_result=Zero exit /B 0 ) set counter=0 set parse_number_result= :parse_number_loop set last_three=%number:~-3% set number=%number:~0,-3% call :parse_three %last_three% call :get_from %counter% %big_numbers% if "$%get_from_result%" == "$" ( set parse_number_result=* ERR: the number is too big! Even wikipedia doesn't know how it's called! exit /B 0 ) if not "$%parse_three_result%" == "$Zero" ( if %counter% == 0 ( set parse_number_result=%parse_three_result% ) else ( if not "$%parse_number_result%" == "$" ( set parse_number_result=%parse_three_result% %get_from_result% %parse_number_result% ) else ( set parse_number_result=%parse_three_result% %get_from_result% ) ) ) set /A counter+=1 if not "$%number%" == "$" goto parse_number_loop if "$%parse_number_result%" == "$" ( set parse_number_result=Zero exit /B 0 ) else if not "$%number_sign%" == "$" ( set parse_number_result=%number_sign% %parse_number_result% ) exit /B 0 :parse_three call :trim_leading_zeros %~1 set three=%trim_leading_zeros_result% set /A three=%three% %% 1000 set /A two=%three% %% 100 call :parse_two %two% set parse_three_result= set /A digit=%three% / 100 if not "$%digit%" == "$0" ( call :get_from %digit% %zero_to_nineteen% ) if not "$%digit%" == "$0" ( if not "$%get_from_result%" == "$Zero" ( set parse_three_result=%get_from_result% Hundred ) ) if "$%parse_two_result%" == "$Zero" ( if "$%parse_three_result%" == "$" ( set parse_three_result=Zero ) ) else ( if "$%parse_three_result%" == "$" ( set parse_three_result=%parse_two_result% ) else ( set parse_three_result=%parse_three_result% %parse_two_result% ) ) exit /B 0 :parse_two call :trim_leading_zeros %~1 set two=%trim_leading_zeros_result% set /A two=%two% %% 100 call :get_from %two% %zero_to_nineteen% if not "$%get_from_result%" == "$" ( set parse_two_result=%get_from_result% goto parse_two_20_end ) set /A digit=%two% %% 10 call :get_from %digit% %zero_to_nineteen% set parse_two_result=%get_from_result% set /A digit=%two% / 10 call :get_from %digit% %twenty_to_ninety% if not "$%parse_two_result%" == "$Zero" ( set parse_two_result=%get_from_result% %parse_two_result% ) else ( set parse_two_result=%get_from_result% ) goto parse_two_20_end :parse_two_20_end exit /B 0 :get_from call :trim_leading_zeros %~1 set idx=%trim_leading_zeros_result% set /A idx=0+%~1 shift :get_from_loop if "$%idx%" == "$0" goto get_from_loop_end set /A idx-=1 shift goto get_from_loop :get_from_loop_end set get_from_result=%~1 exit /B 0 :trim_leading_zeros set str=%~1 set trim_leading_zeros_result= :trim_leading_zeros_loop if not "$%str:~0,1%" == "$0" ( set trim_leading_zeros_result=%trim_leading_zeros_result%%str% exit /B 0 ) set str=%str:~1% if not "$%str%" == "$" goto trim_leading_zeros_loop if "$%trim_leading_zeros_result%" == "$" set trim_leading_zeros_result=0 exit /B 0 :get_sign set str=%~1 set sign=%str:~0,1% set get_sign_result= if "$%sign%" == "$-" ( set get_sign_result=Minus set get_sign_result_number=%str:~1% ) else if "$%sign%" == "$+" ( set get_sign_result_number=%str:~1% ) else ( set get_sign_result_number=%str% ) exit /B 0 :remove_groups set str=%~1 set remove_groups_result=%str:'=% exit /B 0 

这是我使用的testing脚本:

 @echo off rem 10^x:x= 66 63 60 57 54 51 48 45 42 39 36 33 30 27 24 21 18 15 12 9 6 3 0 call number 0 call number 2 call number -17 call number 30 call number 48 call number -256 call number 500 call number 874 call number 1'024 call number -17'001 call number 999'999 call number 1'048'576 call number -1'000'001'000'000 call number 912'345'014'587'957'003 call number -999'912'345'014'587'124'337'999'999 call number 111'222'333'444'555'666'777'888'999'000'000'000'001 call number -912'345'014'587'912'345'014'587'124'912'345'014'587'124'337 call number 999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999 call number 1'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000 rem 10^x:x= 66 63 60 57 54 51 48 45 42 39 36 33 30 27 24 21 18 15 12 9 6 3 0 

这是我从testing脚本得到的输出:

 0 -> Zero 2 -> Two -17 -> Minus Seventeen 30 -> Thirty 48 -> Forty Eight -256 -> Minus Two Hundred Fifty Six 500 -> Five Hundred 874 -> Eight Hundred Seventy Four 1'024 -> One Thousand Twenty Four -17'001 -> Minus Seventeen Thousand One 999'999 -> Nine Hundred Ninety Nine Thousand Nine Hundred Ninety Nine 1'048'576 -> One Million Forty Eight Thousand Five Hundred Seventy Six -1'000'001'000'000 -> Minus One Trillion One Million 912'345'014'587'957'003 -> Nine Hundred Twelve Quadrillion Three Hundred Forty Five Trillion Fourteen Billion Five Hundred Eighty Seven Million Nine Hundred Fifty Seven Thousand Three -999'912'345'014'587'124'337'999'999 -> Minus Nine Hundred Ninety Nine Septillion Nine Hundred Twelve Sextillion Three Hundred Forty Five Quintillion Fourteen Quadrillion Five Hundred Eighty Seven Trillion One Hundred Twenty Four Billion Three Hundred Thirty Seven Million Nine Hundred Ninety Nine Thousand Nine Hundred Ninety Nine 111'222'333'444'555'666'777'888'999'000'000'000'001 -> One Hundred Eleven Undecillion Two Hundred Twenty Two Decillion Three Hundred Thirty Three Nonillion Four Hundred Forty Four Octillion Five Hundred Fifty Five Septillion Six Hundred Sixty Six Sextillion Seven Hundred Seventy Seven Quintillion Eight Hundred Eighty Eight Quadrillion Nine Hundred Ninety Nine Trillion One -912'345'014'587'912'345'014'587'124'912'345'014'587'124'337 -> Minus Nine Hundred Twelve Tredecillion Three Hundred Forty Five Duodecillion Fourteen Undecillion Five Hundred Eighty Seven Decillion Nine Hundred Twelve Nonillion Three Hundred Forty Five Octillion Fourteen Septillion Five Hundred Eighty Seven Sextillion One Hundred Twenty Four Quintillion Nine Hundred Twelve Quadrillion Three Hundred Forty Five Trillion Fourteen Billion Five Hundred Eighty Seven Million One Hundred Twenty Four Thousand Three Hundred Thirty Seven 999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999'999 -> Nine Hundred Ninety Nine Vigintillion Nine Hundred Ninety Nine Novemdecillion Nine Hundred Ninety Nine Octodecillion Nine Hundred Ninety Nine Septendecillion Nine Hundred Ninety Nine Sexdecillion Nine Hundred Ninety Nine Quindecillion Nine Hundred Ninety Nine Quattuordecillion Nine Hundred Ninety Nine Tredecillion Nine Hundred Ninety Nine Duodecillion Nine Hundred Ninety Nine Undecillion Nine Hundred Ninety Nine Decillion Nine Hundred Ninety Nine Nonillion Nine Hundred Ninety Nine Octillion Nine Hundred Ninety Nine Septillion Nine Hundred Ninety Nine Sextillion Nine Hundred Ninety Nine Quintillion Nine Hundred Ninety Nine Quadrillion Nine Hundred Ninety Nine Trillion Nine Hundred Ninety Nine Billion Nine Hundred Ninety Nine Million Nine Hundred Ninety Nine Thousand Nine Hundred Ninety Nine 1'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000'000 -> * ERR: the number is too big! Even wikipedia doesn't know how it's called! 

如果我能find更多的大数字的话 ,这个脚本将会支持更多的数字。 目前,脚本将使用从(10 ^ 66-1)到(10 ^ 66-1)的所有数字。

我不得不提,我在BATCH解决这个问题有很多乐趣。 🙂

C# – 30行, 方法声明和{} s

考虑到所有前面提到的逗号,和连字符。 我只包括octillion,因为decimal.MaxValue只在octillions中。 对于更大的整数,您需要将相应的项目添加到thou []数组中,并可能将该数字作为string传递,修改该行以通过使用最后3个字符来提取块,而不是像我在这里那样使用模数。

  static string wordify(decimal v) { if (v == 0) return "zero"; var units = " one two three four five six seven eight nine".Split(); var teens = " eleven twelve thir# four# fif# six# seven# eigh# nine#".Replace("#", "teen").Split(); var tens = " ten twenty thirty forty fifty sixty seventy eighty ninety".Split(); var thou = " thousand m# b# tr# quadr# quint# sext# sept# oct#".Replace("#", "illion").Split(); var g = (v < 0) ? "minus " : ""; var w = ""; var p = 0; v = Math.Abs(v); while (v > 0) { int b = (int)(v % 1000); if (b > 0) { var h = (b / 100); var t = (b - h * 100) / 10; var u = (b - h * 100 - t * 10); var s = ((h > 0) ? units[h] + " hundred" + ((t > 0 | u > 0) ? " and " : "") : "") + ((t > 0) ? (t == 1 && u > 0) ? teens[u] : tens[t] + ((u > 0) ? "-" : "") : "") + ((t != 1) ? units[u] : ""); s = (((v > 1000) && (h == 0) && (p == 0)) ? " and " : (v > 1000) ? ", " : "") + s; w = s + " " + thou[p] + w; } v = v / 1000; p++; } return g + w; } 

调用使用:

 static void Main(string[] args) { Console.WriteLine(wordify(decimal.MaxValue)); } 

输出:

七十九件,二百二十八件,一百六十二件,五百一十四件,二百六十四万亿,三十七万七千亿,五十九亿三十亿五千四百三十九万五千三百三十五

在A86中 – 组装到.COM可执行文件:

 dd 0ba02c6bfh, 0b8bd10c1h, 0e808b512h, 0ea870100h, 08700e9e8h, 010273eah dd 0e0e8c2h, 06b51872h, 0c000ebe8h, 0b3c02e8h, 03368067dh, 0b2e901h dd 0baaa5004h, 0fd8110c1h, 0cd7c1630h, 0bf3031bbh, 0a0571000h, 0ec880080h dd 0c581c589h, 023c0081h, 0e7f087ch, 0823e38h, 027b00875h, 0e901d068h dd 0b6400080h, 04f6f603h, 080d08a1ch, 0b60f80c4h, 07f06c7f4h, 088303000h dd 0ac00813eh, 087ef828h, 0b00056e8h, 051e81dh, 0d83850adh, 0e7f157ch dd 0a74fc38h, 0262ce088h, 0e901a368h, 01d2c003bh, 0580036e8h, 0b7efc38h dd 0774d838h, 0f828e088h, 0800026e8h, 0127e1dfah, 0afd448ah, 0440afe44h dd 074f838ffh, 0e8c28a05h, 0cafe000fh, 0ab7cee39h, 05a2405c6h, 021cd09b4h dd 05e856c3h, 020b05e00h, 0c5bec3aah, 074c00a02h, 03c80460ah, 0fefa755bh dd 046f675c8h, 0745b3cach, 0f8ebaae8h, 0eec1d689h, 08a3c8a03h, 07e180cah dd 0cfd2c1feh, 0ebe8c342h, 0fed8d0ffh, 0c3f775cdh, 01e581e8fh, 0303c5ea8h dd 0df6f652ah, 078bde03ch, 05e027500h, 01ec1603ch, 07d40793dh, 0603c8080h dd 09f6f2838h, 040f17a3dh, 080f17a22h, 0403d7264h, 0793cdee1h, 0140740f1h dd 01e2f7d32h, 02f488948h, 0a7c43b05h, 0a257af9bh, 0be297b6ch, 04609e30ah dd 0b8f902abh, 07c21e13eh, 09a077d9eh, 054f82ab5h, 0fabe2af3h, 08a6534cdh dd 0d32b4c97h, 035c7c8ceh, 082bcc833h, 0f87f154fh, 0650ff7eah, 02f143fdfh dd 0a1fd687fh, 0c3e687fdh, 0c6d50fe0h, 075f13574h, 0898c335bh, 0e748ce85h dd 08769676fh, 0ad2cedd3h, 0928c77c7h, 077e2d18eh, 01a77e8f6h db 0bah, 01bh 

这是一个454字节的可执行文件。

这是(稍小)的代码。 由于A86是一个8086汇编程序,我不得不手动编写32位扩展:

  mov di,strings mov dx,tree_data * 8 + 1 mov bp,code_data * 8 l1: mov ch,8 call extract_bits xchg dx,bp call extract_bit xchg dx,bp jnc l2 add dx,ax l2: call extract_bit jc l3 mov ch,6 call extract_bits shr al,2 cmp al,11 push l27 jl get_string l25: add al,48+32 stosb l27: mov dx,tree_data * 8 + 1 l3: cmp bp,end_data * 8 jl l1 convert: mov bx,'01' mov di,01000h push di mov al,[80h] mov ah,ch mov bp,ax add bp,81h cmp al,2 jl zero jg l90 cmp byte ptr [82h],bh jne l90 zero: mov al,39 push done get_string: mov si,strings-1 or al,al je l36 l35: inc si cmp byte ptr [si],';'+32 jne l35 dec al jnz l35 l36: inc si l37: lodsb cmp al,';'+32 je ret stosb jmp l37 l90: inc ax mov dh,3 div dh add al,28 mov dl,al add ah,80h db 0fh, 0b6h, 0f4h ; movzx si,ah mov word ptr [80h],'00' l95: lodsb sub al,bh jle l100 call get_string2 mov al,29 call get_string2 l100: lodsw push ax cmp al,bl jl l150 jg l140 cmp ah,bh je l140 mov al,ah sub al,'0'-10 push l150 get_string2: push si call get_string pop si mov al,' ' stosb ret l140: sub al,'0'-19 call get_string2 l150: pop ax cmp ah,bh jle l200 cmp al,bl je l200 mov al,ah sub al,bh call get_string2 l200: cmp dl,29 jle l300 mov al,[si-3] or al,[si-2] or al,[si-1] cmp al,bh je l300 mov al,dl call get_string2 l300: dec dl cmp si,bp jl l95 done: mov byte ptr [di],'$' pop dx mov ah,9 int 21h int 20h l41: rcr al,1 dec ch jz ret extract_bits: push l41 extract_bit: mov si,dx shr si,3 mov bh,[si] mov cl,dl and cl,7 inc cl ror bh,cl inc dx ret tree_data: dw 01e8fh, 01e58h, 05ea8h, 0303ch, 0652ah, 0df6fh, 0e03ch, 078bdh dw 07500h, 05e02h, 0603ch, 01ec1h, 0793dh, 07d40h, 08080h, 0603ch dw 02838h, 09f6fh, 07a3dh, 040f1h, 07a22h, 080f1h, 07264h, 0403dh dw 0dee1h, 0793ch, 040f1h, 01407h, 07d32h, 01e2fh, 08948h db 048h code_data: dw 052fh, 0c43bh, 09ba7h, 057afh, 06ca2h, 0297bh, 0abeh, 09e3h dw 0ab46h, 0f902h, 03eb8h, 021e1h, 09e7ch, 077dh, 0b59ah, 0f82ah dw 0f354h, 0be2ah, 0cdfah, 06534h, 0978ah, 02b4ch, 0ced3h, 0c7c8h dw 03335h, 0bcc8h, 04f82h, 07f15h, 0eaf8h, 0ff7h, 0df65h, 0143fh dw 07f2fh, 0fd68h, 0fda1h, 0e687h, 0e0c3h, 0d50fh, 074c6h, 0f135h dw 05b75h, 08c33h, 08589h, 048ceh, 06fe7h, 06967h, 0d387h, 02cedh dw 0c7adh, 08c77h, 08e92h, 0e2d1h, 0f677h, 077e8h, 0ba1ah db 01bh end_data: strings: 

文本使用霍夫曼编码进行存储。 命令行是作为一个string传递的,所以转换它很简单 – 将string拆分为三个组,然后parsing每个组(数百,数十和单位),每个组使用当前乘数(百万,千等)。

C ++,15行:

 #include <string> using namespace std; string Thousands[] = { "zero", "thousand", "million", "billion", "trillion", "quadrillion", "quintillion", "sexillion", "septillion", "octillion", "nonillion", "decillion" }; string Ones[] = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" }; string Tens[] = { "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" }; string concat(bool cond1, string first, bool cond2, string second) { return (cond1 ? first : "") + (cond1 && cond2 ? " " : "") + (cond2 ? second : ""); } string toStringBelowThousand(unsigned long long n) { return concat(n >= 100, Ones[n / 100] + " hundred", n % 100 != 0, (n % 100 < 20 ? Ones[n % 100] : Tens[(n % 100) / 10] + (n % 10 > 0 ? " " + Ones[n % 10] : ""))); } string toString(unsigned long long n, int push = 0) { return n == 0 ? "zero" : concat(n >= 1000, toString(n / 1000, push + 1), n % 1000 != 0, concat(true, toStringBelowThousand(n % 1000), push > 0, Thousands[push])); } 

用法:

 cout << toString(51351); // => fifty one thousand three hundred fifty one 

这是作弊吗?

 perl -MNumber::Spell -e 'print spell_number(2);' 

保罗·菲舍尔(Paul Fischer)和大stream士(Darius):你们有一些很棒的想法,但是我讨厌看到他们以这种过度冗长的方式来实施。 :)只是在开玩笑,你的解决scheme真棒,但我挤出14 30多个字节出来,同时留在79列和保持python 3兼容性。

所以这里是我的416字节的python79列(谢谢你,我站在你的肩上)

 w=lambda n:_(n,["","thousand "]+p("mb tr quadr quint","illion"))[:-1]or"zero" _=lambda n,S:n*"x"and _(n//M,S[1:])+(Z[n%M//C]+"hundred ")*(n%M//C>0)+(n%C>19 and p("twen thir fo"+R,"ty")[n%C//10-2]+Z[n%10]or Z[n%C])+S[0]*(n%M>0) p=lambda a,b="":[i+b+" "for i in a.split()] R="r fif six seven eigh nine" M=1000 C=100 Z=[""]+p("one two three four five%st nine ten eleven twelve"%R[5:20])+p( "thir fou"+R,"teen") 

而testing:

 if __name__ == "__main__": import sys assert(w(0)=="zero") assert(w(100)=="one hundred") assert(w(1000000)=="one million") assert(w(1024)=="one thousand twenty four") assert(w(1048576)=="one million forty eight thousand five hundred seventy six") 

看recursion的更好的答案。 这是更好的方式。

疯狂的道具大stream士在这一个灵感。 你的大W (现在我的p )特别聪明。

 w=lambda n:["zero"," ".join(_(n,0))][n>0] _=lambda n,l:_(n//M,l+1)+[E,Z[n%M//C]+["hundred"]][n%M//C>0]+\ (p("twen thir fo"+R,"ty")[n%C//10-2]+Z[n%10]if n%C>19 else Z[n%C])+\ [E,([E,["thousand"]]+p("mb tr quadr quint","illion"))[l]][n%M>0]if n else E p=lambda a,b:[[i+b]for i in a.split()] E=[];R="r fif six seven eigh nine";M=1000;C=100 Z=[E]+p("one two three four five six seven eight nine ten eleven twelve","")+\ p("thir fou"+R,"teen") 

我用这个testing它:

 if __name__ == "__main__": import sys print w(int(sys.argv[1])) assert(w(100)=="one hundred") assert(w(1000000)=="one million") assert(w(1024)=="one thousand twenty four") assert(w(1048576)=="one million forty eight thousand five hundred seventy six") 

在这一点上,这是对大stream士目前的解决scheme的一个调整,这反过来又是我的老调整的一个调整,这是从他的启发,他在评论中给了一些错误提示。 这也是对Python的犯罪。

下面的剧透, rot13'd为您的保护,因为一半的高尔夫搞清楚如何的乐趣。 我强烈build议mnenhy Firefox扩展插件来解码这个(和其他简单的编码scheme)。

Pbafgnagf(V eranzrq gurz guvf erivfvba gb ubcrshyyl znxr gurz pyrnere。)

  • R :Gur rzcgl frg。
  • E :Gung juvpu vf va pbzzba orgjrra pbhagvat va gur“grraf”( e grra, svs grra, fvk grra …)naq va gur graf( e gl, svs gl, fvk gl ….)
  • ZP :荣格·格勒·阿尔纳(Ebzna ahzrenyf)。
  • M :Nyy gur ahzoref sebz bar gb gjragl。

Shapgvbaf(fbzr nyfb eranzrq guvf ebhaq)

  • j :Gur choyvp-snpvat shapgvba,juvpu gheaf n ahzore vagb jbeqf。
  • _ :Erphefviryl gheaf gur ahzore vagb jbeqf,gubhfnaq-ol-gubhfnaq。 a vf gur ahzore, y vf ubj sne guebhtu gur cbjref bs 1000 jr ner。 Ergheaf n yvfg bs fvatyrgba yvfgf bs rnpu jbeq va gur ahzore,rt [['bar'],['gubhfnaq'],['gjragl'],['sbhe']]
  • c :sbe rnpu jbeq va gur fcnpr-frcnengrq jbeq yvfg n ,nccraqf o nf n fhssvk naq chgf gurz rnpu vagb n fvatyrgba yvfg。 Sbe rknzcyr, c("zo ge","vyyvba") == [['zvyyvba'],['ovyyvba'],['gevyyvba']]

Python,446字节。 所有80行以下的行,都不敢苟同。 这是Paul Fisher的解决scheme ,在他的488字节版本的基础上,几乎在每一行都进行了编码调整。 他已经挤出了几个字节,我承认。 去投票给他的答案!

 g=lambda n:["zero"," ".join(w(n,0))][n>0] w=lambda n,l:w(n//m,l+1)+[e,z[n%m//100]+["hundred"]][n%m//100>0]+\ (p("twen thir fo"+r,"ty")[n%100//10-2]+z[n%10]if n%100>19 else z[n%100])+\ [e,k[l]][n%m>0]if n else e p=lambda a,b:[[i+b]for i in a.split()] e=[];r="r fif six seven eigh nine";m=1000 k=[e,["thousand"]]+p("mb tr quadr quint","illion") z=[e]+p("one two three four five six seven eight nine ten eleven twelve","")+\ p("thir fou"+r,"teen") 

历史变得复杂了。 我从下面的未混淆的代码开始,它支持负数和范围检查,加上一些数字中的破折号来提高英语水平:

 >>> n2w(2**20) 'one million forty-eight thousand five hundred seventy-six' def n2w(n): if n < 0: return 'minus ' + n2w(-n) if n < 10: return W('zero one two three four five six seven eight nine')[n] if n < 20: return W('ten eleven twelve', 'thir four fif six seven eigh nine', 'teen')[n-10] if n < 100: tens = W('', 'twen thir for fif six seven eigh nine', 'ty')[n//10-2] return abut(tens, '-', n2w(n % 10)) if n < 1000: return combine(n, 100, 'hundred') for i, word in enumerate(W('thousand', 'mb tr quadr quint', 'illion')): if n < 10**(3*(i+2)): return combine(n, 10**(3*(i+1)), word) assert False def W(b, s='', suff=''): return b.split() + [s1 + suff for s1 in s.split()] def combine(n, m, term): return abut(n2w(n // m) + ' ' + term, ' ', n2w(n % m)) def abut(w10, sep, w1): return w10 if w1 == 'zero' else w10 + sep + w1 

然后,我通过混淆(新对我来说)将它压缩到540字节左右,Paul Fisher发现了一个较短的algorithm(丢掉了破折号)以及一些非常可怕的Python编码技巧。 我偷了编码技巧到508(仍然没有赢)。 我试着重新启动一个新的algorithm,这是无法击败费舍尔。 最后这里是他的代码的调整。 尊重!

被混淆的代码已经被testing了干净的代码,这是由一群案件的眼球检查。

好吧,这里是F#,试图保持可读性,大约830字节:

 #light let thou=[|"";"thousand";"million";"billion";"trillion";"quadrillion";"quintillion"|] let ones=[|"";"one";"two";"three";"four";"five";"six";"seven";"eight";"nine";"ten";"eleven"; "twelve";"thirteen";"fourteen";"fifteen";"sixteen";"seventeen";"eighteen";"nineteen"|] let tens=[|"";"";"twenty";"thirty";"forty";"fifty";"sixty";"seventy";"eighty";"ninety"|] let (^-) xy = if y="" then x else x^"-"^y let (^+) xy = if y="" then x else x^" "^y let (^?) xy = if x="" then x else x^+y let (+^+) xy = if x="" then y else x^+y let Tiny n = if n < 20 then ones.[n] else tens.[n/10] ^- ones.[n%10] let Small n = (ones.[n/100] ^? "hundred") +^+ Tiny(n%100) let rec Big nt = if n = 0UL then "" else (Big (n/1000UL) (t+1)) +^+ (Small(n%1000UL|>int) ^? thou.[t]) let Convert n = if n = 0UL then "zero" else Big n 0 

这里是unit testing

 let Show n = printfn "%20u -> \"%s\"" n (Convert n) let tinyTests = [0; 1; 10; 11; 19; 20; 21; 30; 99] |> List.map uint64 let smallTests = tinyTests @ (tinyTests |> List.map (fun n -> n + 200UL)) let MakeTests t1 t2 = List.map (fun n -> n * (pown 1000UL t1)) smallTests |> List.map_concat (fun n -> List.map (fun x -> x * (pown 1000UL t2) + n) smallTests) for n in smallTests do Show n for n in MakeTests 1 0 do Show n for n in MakeTests 5 2 do Show n Show 1000001000678000001UL Show 17999999999999999999UL 

这里是一个相对简单的C语言实现(52行)。

注意 :这不会执行任何边界检查; 调用者必须确保调用缓冲区足够大。

 #include <stdio.h> #include <string.h> const char *zero_to_nineteen[20] = {"", "One ", "Two ", "Three ", "Four ", "Five ", "Six ", "Seven ", "Eight ", "Nine ", "Ten ", "Eleven ", "Twelve ", "Thirteen ", "Fourteen ", "Fifteen ", "Sixteen ", "Seventeen ", "Eighteen ", "Nineteen "}; const char *twenty_to_ninety[8] = {"Twenty ", "Thirty ", "Forty ", "Fifty ", "Sixty ", "Seventy ", "Eighty ", "Ninety "}; const char *big_numbers[7] = {"", "Thousand ", "Million ", "Billion ", "Trillion ", "Quadrillion ", "Quintillion "}; void num_to_word(char *buf, unsigned long long num) { unsigned long long power_of_1000 = 1000000000000000000ull; int power_index = 6; if(num == 0) { strcpy(buf, "Zero"); return; } buf[0] = 0; while(power_of_1000 > 0) { int group = num / power_of_1000; if(group >= 100) { strcat(buf, zero_to_nineteen[group / 100]); strcat(buf, "Hundred "); group %= 100; } if(group >= 20) { strcat(buf, twenty_to_ninety[group / 10 - 2]); group %= 10; } if(group > 0) strcat(buf, zero_to_nineteen[group]); if(num >= power_of_1000) strcat(buf, big_numbers[power_index]); num %= power_of_1000; power_of_1000 /= 1000; power_index--; } buf[strlen(buf) - 1] = 0; } 

这里有一个更混乱的版本(682个字符)。 如果我真的尝试过,可能会减less一点点。

 #include <string.h> #define C strcat(b, #define U unsigned long long char*z[]={"","One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Eleven","Twelve","Thirteen","Fourteen","Fifteen","Sixteen","Seventeen","Eighteen","Nineteen"},*t[]={"Twenty ","Thirty ","Forty ","Fifty ","Sixty ","Seventy ","Eighty ","Ninety "},*q[]={"","Thousand ","Million ","Billion ","Trillion ","Quadrillion ","Quintillion "}; void W(char*b,U n){U p=1000000000000000000ull;int i=6;*b=0;if(!n)strcpy(b,"Zero ");else while(p){int g=n/p;if(g>99){C z[g/100]);C " ");C "Hundred ");g%=100;}if(g>19){C t[g/10-2]);g%=10;}if(g)C z[g]),C " ");if(n>=p)C q[i]);n%=p;p/=1000;i--;}b[strlen(b)-1]=0;} 

一个T-SQL(SQL Server 2005)函数,包括testing用例:

 if exists (select 1 from sys.objects where object_id = object_id(N'dbo.fnGetNumberString')) drop function fnGetNumberString go /* Tests: declare @tests table ( testValue bigint ) insert into @tests select -43213 union select -5 union select 0 union select 2 union select 15 union select 33 union select 100 union select 456 union select 1024 union select 10343 union select 12345678901234 union select -3434343434343 select testValue, dbo.fnGetNumberString(testValue) as textValue from @tests */ create function dbo.fnGetNumberString ( @value bigint ) returns nvarchar(1024) as begin if @value = 0 return 'zero' -- lets me avoid special-casing this later declare @isNegative bit set @isNegative = 0 if @value < 0 select @isNegative = 1, @value = @value * -1 declare @groupNames table ( groupOrder int, groupName nvarchar(15) ) insert into @groupNames select 1, '' union select 2, 'thousand' union select 3, 'million' union select 4, 'billion' union select 5, 'trillion' union select 6, 'quadrillion' union select 7, 'quintillion' union select 8, 'sextillion' declare @digitNames table ( digit tinyint, digitName nvarchar(10) ) insert into @digitNames select 0, '' union select 1, 'one' union select 2, 'two' union select 3, 'three' union select 4, 'four' union select 5, 'five' union select 6, 'six' union select 7, 'seven' union select 8, 'eight' union select 9, 'nine' union select 10, 'ten' union select 11, 'eleven' union select 12, 'twelve' union select 13, 'thirteen' union select 14, 'fourteen' union select 15, 'fifteen' union select 16, 'sixteen' union select 17, 'seventeen' union select 18, 'eighteen' union select 19, 'nineteen' declare @tensGroups table ( digit tinyint, groupName nvarchar(10) ) insert into @tensGroups select 2, 'twenty' union select 3, 'thirty' union select 4, 'forty' union select 5, 'fifty' union select 6, 'sixty' union select 7, 'seventy' union select 8, 'eighty' union select 9, 'ninety' declare @groups table ( groupOrder int identity, groupValue int ) declare @convertedValue varchar(50) while @value > 0 begin insert into @groups (groupValue) select @value % 1000 set @value = @value / 1000 end declare @returnValue nvarchar(1024) set @returnValue = '' if @isNegative = 1 set @returnValue = 'negative' select @returnValue = @returnValue + case when len(h.digitName) > 0 then ' ' + h.digitName + ' hundred' else '' end + case when len(isnull(t.groupName, '')) > 0 then ' ' + t.groupName + case when len(isnull(o.digitName, '')) > 0 then '-' else '' end + isnull(o.digitName, '') else case when len(isnull(o.digitName, '')) > 0 then ' ' + o.digitName else '' end end + case when len(n.groupName) > 0 then ' ' + n.groupName else '' end from @groups g join @groupNames n on n.groupOrder = g.groupOrder join @digitNames h on h.digit = (g.groupValue / 100) left join @tensGroups t on t.digit = ((g.groupValue % 100) / 10) left join @digitNames o on o.digit = case when (g.groupValue % 100) < 20 then g.groupValue % 100 else g.groupValue % 10 end order by g.groupOrder desc return @returnValue end go 

Here's a Scala solution. I'm not happy about trying to make it look short — I sacrificed a bit of readability 🙁

object NumSpeller {
  val digits = Array("","one","two","three","four","five","six","seven","eight","nine")
  val teens = Array("ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen")
  val tens = Array("", "ten", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety")
  val thousands = Array("", "thousand", "million", "billion", "trillion", "quadrillion", "quintillion")

  def spellGroup(num:Int) = {
    val (v3, v2, v1) = ((num / 100) % 10, (num / 10) % 10, num % 10)
    val hs = v3 match { case 0 => ""; case d => digits(d) + " hundred " }
    val ts = v2 match {
      case 0 => digits(v1)
      case 1 => teens(v1)
      case _ => v3 match { case 0 => tens(v2); case _ => tens(v2) + "-" + digits(v1) }
     }
    hs + ts
   }

  def numberGroups(num:Long) = {
    def _numberGroups(num:Long, factor:Int):List[(Double,Int)] = factor match {
      case 0 => List((num % 1000,0))
      case _ => ((num / Math.pow(1000, factor)) % 1000, factor) :: _numberGroups(num, factor - 1)
     }
    val ints = _numberGroups(num, 6) map (x => (x._1.asInstanceOf[Int],x._2))
    ints dropWhile (x => x._1 == 0.0)
   }

  def spell(num:Long) = num match { case 0 => "zero"; case _ => (numberGroups(num) map { x => spellGroup(x._1) + " " + thousands(x._2) + " " }).mkString.trim }
 }

用法是:

 NumSpeller.spell(458582) 

Perl 5.10

 my %expo=(0,'', qw'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' ); my %digit=(0,'', qw'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 2* twenty 3* thirty 4* forty 5* fifty 6* sixty 7* seventy 8* eighty 9* ninety' ); sub spell_number(_){ local($_)=@_; ($_,@_)=split/(?=(?:.{3})*+$)/; $_=0 x(3-length).$_; unshift@_,$_; my @o; my $c=@_; for(@_){ my $o=''; /(.)(.)(.)/; $o.=$1?$digit{$1}.' hundred':''; $o.=$2==1? ' '.$digit{$2.$3} : ($2?' '.$digit{"$2*"}:''). ($2&&$3?' ':''). $digit{$3} ; $o.=--$c?($o?' '.$expo{$c}.', ':''):''; push@o,$o; } my $o; $o.=$_ for@o; $o=~/^\s*+(.*?)(, )?$/; $o?$1:'zero'; } 

笔记:

  • This almost works on earlier Perls, it's that first split() that seems to be the main problem. As it sits now the strings take up the bulk of the characters.
  • I could have shortened it, by removing the my 's, and the local , as well as putting it all on one line.
  • I used Number::Spell as a starting point.
  • Works under strict and warnings .

Mmm, you might have put the bar a bit high, both on the limit (18,446,744,073,709,552,000, I don't even know how to write that!) and on the goal (the other code golfs resulted in short code, this one will be long at least for the data (words)).

Anyway, for the record, I give an well known solution (not mine!) for French, in PHP: Écriture des nombres en français . 🙂

Note the ambiguity (voluntary or not) of your wording: " Submissions in any language welcome "
I first took it as "natural language", before understand you probably meant "programming language…
The algorithm is probably simpler in English (and with less regional variants…).

In the D programming language

 string Number(ulong i) { static string[] names = [ ""[], " thousand", " million", " billion", " trillion", " quadrillion", ]; string ret = null; foreach(mult; names) { if(i%1000 != 0) { if(ret != null) ret = ret ~ ", " ret = Cent(i%1000) ~ mult ~ ret; } i /= 1000; } return ret; } string Cent(int i) { static string[] v = [""[], "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]; static string[] tens = ["!"[], "!", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]; string p1, p2, p3 = ""; if(i >= 100) { p1 = v[i/100] ~ " hundred"; p3 = (i % 100 != 0) ? " and " : ""; //optional } else p1 = ""; i %= 100; switch(i) { case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9: p2 = v[i]; break; case 10: p2 = "ten"; break; case 11: p2 = "eleven"; break; case 12: p2 = "twelve"; break; case 13: p2 = "thirteen"; break; case 14: p2 = "fourteen"; break; case 15: p2 = "fifteen"; break; case 16: p2 = "sixteen"; break; case 17: p2 = "seventeen"; break; case 18: p2 = "eighteen"; break; case 19: p2 = "nineteen"; break; default: p2 = tens[i/10] ~ "-" ~ v[i%10]; break; } return p1 ~ p3 ~ p2; } import std.stdio; void main() { writef("%s\n", Number(8_000_400_213)); } 

Try it out here

Does anyone plan on adding the appropriate commas and 'and' any time soon? Or hyphenating twenty-one through ninety-nine? Not much point otherwise, IMHO 🙂

'Nine Hundred Ninety Nine Thousand Nine Hundred Ninety Nine'

VS

'Nine hundred and ninety-nine thousand, nine hundred and ninety-nine'

(And no, mine doesn't work. Yet.)

 #!/usr/bin/env perl my %symbols = ( 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", 20 => "Twenty", 30 => "Thirty", 40 => "Forty", 50 => "Fifty", 60 => "Sixty", 70 => "Seventy", 80 => "Eighty", 90 => "Ninety", 100 => "Hundred"); my %three_symbols = (1 => "Thousand", 2 => "Million", 3 => "Billion" ); sub babo { my ($input) = @_; my @threes = split(undef, $input); my $counter = ($#threes + 1); my $remainder = $counter % 3; my @result; while ($counter > 0){ my $digits = ""; my $three; my $full_match = 0; if ($remainder > 0){ while ($remainder > 0) { $digits .= shift(@threes); $remainder--; $counter--; } } else { $digits = join('',@threes[0,1,2]); splice(@threes, 0, 3); $counter -= 3; } if (exists($symbols{$digits})){ $three = $symbols{$digits}; $full_match = 1; } elsif (length($digits) == 3) { $three = $symbols{substr($digits,0,1)}; $three .= " Hundred"; $digits = substr($digits,1,2); if (exists($symbols{$digits})){ $three .= " " . $symbols{$digits}; $full_match = 1; } } if ($full_match == 0){ $three .= " " . $symbols{substr($digits,0,1)."0"}; $three .= " " . $symbols{substr($digits,1,1)}; } push(@result, $three); if ($counter > 0){ push(@result, "Thousand"); } } my $three_counter = 0; my @r = map {$_ eq "Thousand" ? $three_symbols{++$three_counter}:$_ } reverse @result; return join(" ", reverse @r); } print babo(1) . "\n"; print babo(12) . "\n"; print babo(120) . "\n"; print babo(1234) . "\n"; print babo(12345) . "\n"; print babo(123456) . "\n"; print babo(1234567) . "\n"; print babo(1234567890) . "\n"; 

I can't find the file now, but this was an Intro to Programming problem (late in the term) where I went to school. We had to be able to turn a float into a valid written number for use on a check.

After the assignment was completed the professor showed some C++ code that solved the problem using only concepts we'd already covered. It ran just 43 lines, and was well-documented.

Perl & CPAN working together:

 #!/usr/bin/perl use strict; use warnings; use Lingua::EN::Numbers qw(num2en); print num2en($_), "\n" for 2, 1024, 1024*1024; 
C:\Temp> n.pl
二
one thousand and twenty-four
one million, forty-eight thousand, five hundred and seventy-six 

Here's one in PHP, from Convert Numbers to Words :

 convert_number(2850) 

回报

Two Thousand Eight Hundred and Fifty

and if you want an even more awesome one that handles commas and numbers up to vigintillion check out zac hesters work at Language Display Functions :

 function convert_number($number) { if (($number < 0) || ($number > 999999999)) { throw new Exception("Number is out of range"); } $Gn = floor($number / 1000000); /* Millions (giga) */ $number -= $Gn * 1000000; $kn = floor($number / 1000); /* Thousands (kilo) */ $number -= $kn * 1000; $Hn = floor($number / 100); /* Hundreds (hecto) */ $number -= $Hn * 100; $Dn = floor($number / 10); /* Tens (deca) */ $n = $number % 10; /* Ones */ $res = ""; if ($Gn) { $res .= convert_number($Gn) . " Million"; } if ($kn) { $res .= (empty($res) ? "" : " ") . convert_number($kn) . " Thousand"; } if ($Hn) { $res .= (empty($res) ? "" : " ") . convert_number($Hn) . " Hundred"; } $ones = array("", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eightteen", "Nineteen"); $tens = array("", "", "Twenty", "Thirty", "Fourty", "Fifty", "Sixty", "Seventy", "Eigthy", "Ninety"); if ($Dn || $n) { if (!empty($res)) { $res .= " and "; } if ($Dn < 2) { $res .= $ones[$Dn * 10 + $n]; } else { $res .= $tens[$Dn]; if ($n) { $res .= "-" . $ones[$n]; } } } if (empty($res)) { $res = "zero"; } return $res; } 

A few years ago I created this in C# for multi language applications.

This one is base class:

 public abstract class ValueSource { public abstract object Value { get; } } 

This one is for wordify..

 public abstract class NumberTextValueSource:ValueSource { public abstract decimal Number { get; } public abstract string Format { get; } public abstract string Negative { get; } public abstract bool UseValueIfZero { get; } public abstract string N0 { get; } public abstract string N1 { get; } public abstract string N2 { get; } public abstract string N3 { get; } public abstract string N4 { get; } public abstract string N5 { get; } public abstract string N6 { get; } public abstract string N7 { get; } public abstract string N8 { get; } public abstract string N9 { get; } public abstract string N10 { get; } public abstract string N11 { get; } public abstract string N12 { get; } public abstract string N13 { get; } public abstract string N14 { get; } public abstract string N15 { get; } public abstract string N16 { get; } public abstract string N17 { get; } public abstract string N18 { get; } public abstract string N19 { get; } public abstract string N20 { get; } public abstract string N30 { get; } public abstract string N40 { get; } public abstract string N50 { get; } public abstract string N60 { get; } public abstract string N70 { get; } public abstract string N80 { get; } public abstract string N90 { get; } public abstract string N100 { get; } public abstract string NHundred { get; } public abstract string N1000 { get; } public abstract string NThousand { get; } public abstract string NMillion { get; } public abstract string NBillion { get; } public abstract string NTrillion { get; } public abstract string NQuadrillion { get; } string getOne(Type t, string v) { if (v[0] == '0' && !UseValueIfZero) return ""; return (string)t.GetProperty("N" + v[0].ToString()).GetValue(this, null); } string getTwo(Type t, string v) { if (v[0] == '0') if (v[1] != '0') return getOne(t, v.Substring(1)); else return ""; if (v[1] == '0' || v[0] == '1') return (string)t.GetProperty("N" + v).GetValue(this, null); return (string)t.GetProperty("N" + v[0].ToString() + "0").GetValue(this, null) + getOne(t, v.Substring(1)); } string getThree(Type t, string v) { if(v[0] == '0') return getTwo(t,v.Substring(1)); if (v[0] == '1') return N100 + getTwo(t, v.Substring(1)); return getOne(t, v[0].ToString()) + NHundred + getTwo(t, v.Substring(1)); } string getFour(Type t, string v) { if (v[0] == '0') return getThree(t, v.Substring(1)); if (v[0] == '1') return N1000 + getThree(t, v.Substring(1)); return getOne(t, v[0].ToString()) + NThousand + getThree(t, v.Substring(1)); } string getFive(Type t, string v) { if (v[0] == '0') return getFour(t, v.Substring(1)); return getTwo(t, v.Substring(0, 2)) + NThousand + getThree(t, v.Substring(2)); } string getSix(Type t, string v) { if (v[0] == '0') return getFive(t, v.Substring(1)); return getThree(t, v.Substring(0, 3)) + NThousand + getThree(t, v.Substring(3)); } string getSeven(Type t, string v) { if (v[0] == '0') return getSix(t, v.Substring(1)); return getOne(t, v[0].ToString()) + NMillion + getSix(t, v.Substring(3)); } string getEight(Type t, string v) { if (v[0] == '0') return getSeven(t, v.Substring(1)); return getTwo(t, v.Substring(0, 2)) + NMillion + getSix(t, v.Substring(2)); } string getNine(Type t, string v) { if (v[0] == '0') return getEight(t, v.Substring(1)); return getThree(t, v.Substring(0, 3)) + NMillion + getSix(t, v.Substring(3)); } string getTen(Type t, string v) { if (v[0] == '0') return getNine(t, v.Substring(1)); return getOne(t, v.Substring(0, 1)) + NBillion + getNine(t, v.Substring(1)); } string getEleven(Type t, string v) { if (v[0] == '0') return getTen(t, v.Substring(1)); return getTwo(t, v.Substring(0, 2)) + NBillion + getNine(t, v.Substring(2)); } string getTwelve(Type t, string v) { if (v[0] == '0') return getEleven(t, v.Substring(1)); return getThree(t, v.Substring(0, 3)) + NBillion + getNine(t, v.Substring(3)); } string getThirteen(Type t, string v) { if (v[0] == '0') return getTwelve(t, v.Substring(1)); return getOne(t, v.Substring(0, 1)) + NTrillion + getTwelve(t, v.Substring(1)); } string getForteen(Type t, string v) { if (v[0] == '0') return getThirteen(t, v.Substring(1)); return getTwo(t, v.Substring(0, 2)) + NTrillion + getTwelve(t, v.Substring(2)); } string getFifteen(Type t, string v) { if (v[0] == '0') return getForteen(t, v.Substring(1)); return getThree(t, v.Substring(0, 3)) + NTrillion + getTwelve(t, v.Substring(3)); } string getSixteen(Type t, string v) { if (v[0] == '0') return getFifteen(t, v.Substring(1)); return getOne(t, v.Substring(0, 1)) + NQuadrillion + getFifteen(t, v.Substring(1)); } string getSeventeen(Type t, string v) { if (v[0] == '0') return getSixteen(t, v.Substring(1)); return getTwo(t, v.Substring(0, 2)) + NQuadrillion + getFifteen(t, v.Substring(2)); } string getEighteen(Type t, string v) { if (v[0] == '0') return getSeventeen(t, v.Substring(1)); return getThree(t, v.Substring(0, 3)) + NQuadrillion + getFifteen(t, v.Substring(3)); } string convert(Type t, string hp) { switch (hp.Length) { case 1: return getOne(t, hp); case 2: return getTwo(t, hp); case 3: return getThree(t, hp); case 4: return getFour(t, hp); case 5: return getFive(t, hp); case 6: return getSix(t, hp); case 7: return getSeven(t, hp); case 8: return getEight(t, hp); case 9: return getNine(t, hp); case 10: return getTen(t, hp); case 11: return getEleven(t, hp); case 12: return getTwelve(t, hp); case 13: return getThirteen(t, hp); case 14: return getForteen(t, hp); case 15: return getFifteen(t, hp); case 16: return getSixteen(t, hp); case 17: return getSeventeen(t, hp); case 18: return getEighteen(t, hp); } return ""; } public override object Value { get { decimal d = Number; decimal highPoint, lowPoint; bool isNeg = d < 0; d = Math.Abs(d); highPoint = Math.Floor(d); lowPoint = d - highPoint; Type t = this.GetType(); string strHigh = convert(t, highPoint.ToString()), strLow = lowPoint > 0 ? convert(t, lowPoint.ToString().Substring(2)) : UseValueIfZero ? N0 : ""; if (isNeg) strHigh = Negative + " " + strHigh; return string.Format(Format, strHigh, strLow); } } } 

And this one is for Turkish Lera (TRY):

 public class TRYNumberTextValueSource:NumberTextValueSource { decimal num; public TRYNumberTextValueSource(decimal value) { num = Math.Round(value, 2); } public override decimal Number { get { return num; } } public override string Format { get { if (num == 0) return N0 + " YTL"; if (num > -1 && num < 1) return "{0}{1} Kurus"; return "{0} YTL {1} Kurus"; } } public override string Negative { get { return "-"; } } public override bool UseValueIfZero { get { return false; } } public override string N0 { get { return "sifir"; } } public override string N1 { get { return "bir"; } } public override string N2 { get { return "iki"; } } public override string N3 { get { return "üç"; } } public override string N4 { get { return "dört"; } } public override string N5 { get { return "bes"; } } public override string N6 { get { return "alti"; } } public override string N7 { get { return "yedi"; } } public override string N8 { get { return "sekiz"; } } public override string N9 { get { return "dokuz"; } } public override string N10 { get { return "on"; } } public override string N11 { get { return "onbir"; } } public override string N12 { get { return "oniki"; } } public override string N13 { get { return "onüç"; } } public override string N14 { get { return "ondört"; } } public override string N15 { get { return "onbes"; } } public override string N16 { get { return "onalti"; } } public override string N17 { get { return "onyedi"; } } public override string N18 { get { return "onsekiz"; } } public override string N19 { get { return "ondokuz"; } } public override string N20 { get { return "yirmi"; } } public override string N30 { get { return "otuz"; } } public override string N40 { get { return "kirk"; } } public override string N50 { get { return "elli"; } } public override string N60 { get { return "altmis"; } } public override string N70 { get { return "yetmis"; } } public override string N80 { get { return "seksen"; } } public override string N90 { get { return "doksan"; } } public override string N100 { get { return "yüz"; } } public override string NHundred { get { return "yüz"; } } public override string N1000 { get { return "bin"; } } public override string NThousand { get { return "bin"; } } public override string NMillion { get { return "milyon"; } } public override string NBillion { get { return "milyar"; } } public override string NTrillion { get { return "trilyon"; } } public override string NQuadrillion { get { return "trilyar"; } } } 

And it is used this way:

 MessageBox.show((string)(new TRYNumberTextValueSource(12345)).Value);