代码高尔夫:从数字到单词

发布于 2024-07-08 23:18:21 字数 507 浏览 8 评论 0 原文

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

  • 2 -> 2 两个
  • 1024-> 一千二十四
  • 1048576 -> 一百四十八千五百七十六

我的同事提出的算法几乎有两百行长。 似乎会有一种更简洁的方法来做到这一点。

当前指南:

  • 欢迎以任何编程语言提交(对此我深表歉意) PhiLho 对于这一点最初缺乏清晰度)
  • 最大输入 2^64(请参阅以下单词链接,谢谢 mmeyers)
  • 短规模,首选英文输出,但欢迎任何算法。 只需与编程语言一起注释所使用的方法即可。

The code golf series seem to be fairly popular. I ran across some code that converts a number to its word representation. Some examples would be (powers of 2 for programming fun):

  • 2 -> Two
  • 1024 -> One Thousand Twenty Four
  • 1048576 -> One Million Forty Eight Thousand Five Hundred Seventy Six

The algorithm my co-worker came up was almost two hundred lines long. Seems like there would be a more concise way to do it.

Current guidelines:

  • Submissions in any programming language welcome (I apologize to
    PhiLho for the initial lack of clarity on this one)
  • Max input of 2^64 (see following link for words, thanks mmeyers)
  • Short scale with English output preferred, but any algorithm is welcome. Just comment along with the programming language as to the method used.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(22

深陷 2024-07-15 23:18:21

好的,我想是时候在 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

这是我使用的测试脚本:

@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

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

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!

如果我能找到更多 大数字的名称,脚本将支持更大的数字。 但目前,该脚本将适用于从 -(10^66-1) 到 (10^66-1) 的所有数字。

我不得不提的是,我在 BATCH 中解决这个问题时获得了很多乐趣。 :)

Ok, I think it's time for my own implementation in Windows BATCH script (should work on Windows 2000 or later).

Here is the code:

@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

This is the test script I used:

@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

And this is the output I got from my test script:

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!

If I could find some more names of large numbers, the script would support even bigger numbers. Currently, though, the script will work with all numbers from -(10^66-1) to (10^66-1).

I have to mention, that I had a lot of fun solving this in BATCH. :)

悍妇囚夫 2024-07-15 23:18:21

C# - 30 行,包括 方法声明和 { }s

考虑前面提到的所有逗号、and 和连字符。 我只包含了十亿,因为decimal.MaxValue仅在十亿中。 对于更大的整数,您需要将相应的项目添加到hou[]数组中,并且可能将数字作为字符串传递,修改该行以使用最后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));
}

输出:

七十九八亿,两百
和二十八个七位数,一
一百六十二 六十分, 五
一百一十四五亿,二
一百六十四千万亿,
三百三十七
万亿、五百和
九百三十亿、五百零
四千三百万九百零
五万、三百
三十五

C# - 30 lines incl. method declaration and { }s:

Takes into account all the previously aforementioned commas, ands and hyphens. I've only included up to octillion because decimal.MaxValue is only in the octillions. For bigger integers you would need to add corresponding items to the thou[] array and perhaps pass the number in as a string, modifying the line to extract the block by using the last 3 chars instead of using modulo as I have here.

    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;
    }

Called using:

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

Output:

seventy-nine octillion, two hundred
and twenty-eight septillion, one
hundred and sixty-two sextillion, five
hundred and fourteen quintillion, two
hundred and sixty-four quadrillion,
three hundred and thirty-seven
trillion, five hundred and
ninety-three billion, five hundred and
forty-three million, nine hundred and
fifty thousand, three hundred and
thirty-five

百善笑为先 2024-07-15 23:18:21

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],'

文本使用 Huffman 编码存储。 命令行作为字符串传递,因此转换它很简单 - 将字符串分成三组,并解析每个组(百位、十位和个位),每个组后面跟随当前乘数(百万、千等)。

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:

文本使用 Huffman 编码存储。 命令行作为字符串传递,因此转换它很简单 - 将字符串分成三组,并解析每个组(百位、十位和个位),每个组后面跟随当前乘数(百万、千等)。

In A86 assember - assembles to a .COM executable:

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

That's a 454 byte executable.

Here's the (slightly smaller) code. Since A86 is an 8086 only assembler, I've had to hand code the 32bit extensions:

    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],'

The text is stored using Huffman encoding. The command line is passed as a string so converting it is simple - split the string into groups of three and parse each group (hundreds, tens and units) following each with the current multiplier (millions, thousands, etc).

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:

The text is stored using Huffman encoding. The command line is passed as a string so converting it is simple - split the string into groups of three and parse each group (hundreds, tens and units) following each with the current multiplier (millions, thousands, etc).

花心好男孩 2024-07-15 23:18:21

Lisp,仅使用标准函数:

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

奖励:

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

Lisp, using only standard functions:

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

Bonus:

(format nil "~@r" 1234)  ==> "MCCXXXIV"
方觉久 2024-07-15 23:18:21

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

C++, 15 lines:

#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]));
}

Usage:

cout << toString(51351);   // => fifty one thousand three hundred fifty one
攒眉千度 2024-07-15 23:18:21

这是作弊吗?

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

Is this cheating?

perl -MNumber::Spell -e 'print spell_number(2);'
相守太难 2024-07-15 23:18:21

Paul Fischer 和 Darius:你们有一些很棒的想法,但我讨厌看到它们以如此过于冗长的方式实现。 :) 开个玩笑,你的解决方案很棒,但我又压缩了 14 30 个字节,同时保持在 79 列之内并保持 python 3 兼容性。

这是我的 79 列中的 416 字节 python:(谢谢大家,我站在你们的肩膀上)

w=lambda n:_(n,["","thousand "]+p("m b 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")

和测试:

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")

Paul Fischer and Darius: You guys have some great ideas, but I hate to see them implemented in such an overly verbose fashion. :) Just kidding, your solution is awesome, but I squeezed 14 30 more bytes out, while staying inside of 79 columns and maintaining python 3 compatibility.

So here's my 416 byte python within 79 columns: (thanks guys, I'm standing on your shoulders)

w=lambda n:_(n,["","thousand "]+p("m b 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")

And the tests:

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")
小帐篷 2024-07-15 23:18:21

请参阅递归的更好答案。 好多了。

疯狂地向 Darius 寻求灵感。 你的大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("m b 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")

我用这个测试它:

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")

此时,这是对 Darius 当前解决方案的调整,这又是对我旧解决方案的调整,这是受到他的启发,并且他在评论中给出了一些错误提示。 这也是对Python的犯罪。

下面有剧透,rot13为了保护您,因为高尔夫的一半乐趣
弄清楚如何。 我强烈推荐 mnenhy Firefox
内联解码此(和其他简单编码方案)的扩展。

Pbafgnagf(Veranzrq gurz guvf erivfvba gb ubcrshyyl znxr gurzpynere。)

  • R:Gur rzcgl frg。
  • E:Gung juvpu vf va pbzzba orgjrra pbhagvat va gur "grraf" (egrra,
    svsgrra、fvkgrra...) naq va gur graf (egl、svsgl、 >fvkgl....)
  • ZP:Jung gurl ner va Ebzna ahzrenyf。
  • M:Nyy gur ahzoref sebz bar gb gjragl。

Shapgvbaf(fbzr nyfberanzrq 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。 耳格赫夫
    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']]

See recursive's better answer. It's way betterer.

Mad props to Darius for inspiration on this one. Your big-W (now my p) was especially clever.

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("m b 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")

I test it with this:

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")

At this point, this is a tweak of Darius' current solution, which is in turn a tweak of my older one, which was inspired by his, and he gave some bug hints in the comments. It is also a crime against Python.

Spoilers below, rot13'd for your protection, because half the fun of golf
figuring out how. I highly recommend the mnenhy Firefox
extension to decode this (and other simple encoding schemes) inline.

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" (egrra,
    svsgrra, fvkgrra...) naq va gur graf (egl, svsgl, fvkgl....)
  • Z, P: Jung gurl ner va 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, r.t.
    [['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("z o ge","vyyvba") == [['zvyyvba'],['ovyyvba'],['gevyyvba']].
谈下烟灰 2024-07-15 23:18:21

Python,446 字节。 所有行都在 80 列以下,该死。 这是 Paul Fisher 的解决方案,几乎每一行都进行了编码调整,从他的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("m b 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', 'm b 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 找到了一个更短的算法(去掉破折号)以及一些极其可怕的 Python 编码技巧。 我窃取了编码技巧,将结果降到 508(仍然没有获胜)。 我尝试使用新算法重新启动,但该算法无法击败费舍尔的算法。 最后这是他的代码的调整。 尊重!

混淆后的代码已经针对干净的代码进行了测试,干净的代码是在一堆案例上通过眼球检查的。

Python, 446 bytes. All lines under 80 columns, dammit. This is Paul Fisher's solution with coding tweaks on almost every line, down from his 488-byte version; he's since squeezed out several more bytes, and I concede. Go vote for his answer!

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("m b tr quadr quint","illion")
z=[e]+p("one two three four five six seven eight nine ten eleven twelve","")+\
p("thir fou"+r,"teen")

The history has gotten complicated. I started with the unobfuscated code below, which supports negative numbers and range-checking, plus dashes in some numbers for better English:

>>> 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', 'm b 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

Then I squeezed it to about 540 bytes via obfuscation (new to me), and Paul Fisher found a shorter algorithm (dropping the dashes) along with some marvelously horrible Python coding tricks. I stole the coding tricks to get down to 508 (which still did not win). I tried restarting fresh with a new algorithm, which was unable to beat Fisher's. Finally here's the tweak of his code. Respect!

The obfuscated code has been tested against the clean code, which was checked by eyeball on a bunch of cases.

时光倒影 2024-07-15 23:18:21

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

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

A T-SQL (SQL Server 2005) function, including test cases:

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
影子的影子 2024-07-15 23:18:21

好的,这是 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 (^-) x y = if y="" then x else x^"-"^y
let (^+) x y = if y="" then x else x^" "^y
let (^?) x y = if x="" then x else x^+y
let (+^+) x y = 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 n t = 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

这是单元测试

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

Ok, here's F#, trying to stay readable, at about 830 bytes:

#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 (^-) x y = if y="" then x else x^"-"^y
let (^+) x y = if y="" then x else x^" "^y
let (^?) x y = if x="" then x else x^+y
let (+^+) x y = 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 n t = 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

and here are the unit tests

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
不醒的梦 2024-07-15 23:18:21

这是一个相对简单的 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 个字符)。 如果我真的尝试的话,它可能会减少一点。

#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;}

Here's a relatively straightforward implementation in C (52 lines).

NOTE: this does not perform any bounds checking; the caller must ensure that the calling buffer is large enough.

#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;
}

And here's a much more obfuscated version of that (682 characters). It could probably be pared down a little more if I really tried.

#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;}
一念一轮回 2024-07-15 23:18:21

这是一个 Scala 解决方案。 我不高兴试图让它看起来很短——我牺牲了一点可读性:(

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)

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  }
}

Usage is:

NumSpeller.spell(458582)
倾城花音 2024-07-15 23:18:21

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';
}

注释:

  • 这几乎适用于早期的 Perls,第一个 split() 似乎是主要问题。 现在,字符串占据了大部分字符。
  • 我本可以通过删除 mylocal 来缩短它,并将它们全部放在一行上。
  • 我使用 Number::Spell 作为起点。
  • 严格警告下工作。

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';
}

Notes:

  • 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.
日裸衫吸 2024-07-15 23:18:21

嗯,你可能把门槛设得有点高,无论是在极限(18,446,744,073,709,552,000,我什至不知道如何写!)还是在目标(其他代码高尔夫导致了短代码,这个会很长)至少对于数据(单词))。

无论如何,作为记录,我在 PHP 中给出了一个众所周知的法语解决方案(不是我的!): 法语Écriture des nombres en français。 :-)

请注意您措辞的歧义(自愿或非自愿):“欢迎以任何语言提交
我首先将其视为“自然语言”,然后才理解您可能的意思是“编程语言......
该算法在英语中可能更简单(并且区域变体较少......)。

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...).

韬韬不绝 2024-07-15 23:18:21

D 编程语言

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));
}

在这里尝试一下

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

迷鸟归林 2024-07-15 23:18:21

我现在找不到该文件,但这是我上学时遇到的编程入门问题(学期末)。 我们必须能够将浮点数转换为有效的书面数字以用于支票。

作业完成后,教授展示了一些 C++ 代码,这些代码仅使用我们已经介绍过的概念解决了问题。 它只运行了 43 行,并且有详细的文档记录。

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.

黯淡〆 2024-07-15 23:18:21

有人计划很快添加适当的逗号和“和”吗? 或者用连字符连接二十一到九十九? 否则没有什么意义,恕我直言:)

“九十九九千九百九十九”

“九十九万九千九百九十九”

(不,我的不起作用。但是。)

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.)

叶落知秋 2024-07-15 23:18:21
#!/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";
#!/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";
╰◇生如夏花灿烂 2024-07-15 23:18:21

Perl 和 CPAN 协同工作:

#!/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
two
one thousand and twenty-four
one million, forty-eight thousand, five hundred and seventy-six

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
two
one thousand and twenty-four
one million, forty-eight thousand, five hundred and seventy-six
懷念過去 2024-07-15 23:18:21

几年前,我用 C# 创建了这个用于多语言应用程序。

这个是基类:

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

这个是用于 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);
        }
    }
}

这个是用于土耳其 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"; }
    }
}

它的使用方式是这样的:

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

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);
七颜 2024-07-15 23:18:21

这是 PHP 中的一个,来自 Convert Numbers to Words

convert_number(2850)

返回

两千八百五十

,如果您想要一个更棒的可以处理逗号和数字的工具,请查看 zac hesters 的工作 语言显示函数

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;
}

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

convert_number(2850)

returns

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文