Code Golf: Number to Words

2019-01-02 17:14发布

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.

22条回答
伤终究还是伤i
2楼-- · 2019-01-02 17:52

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
查看更多
只靠听说
3楼-- · 2019-01-02 17:52

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']].
查看更多
零度萤火
4楼-- · 2019-01-02 17:55
#!/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";
查看更多
栀子花@的思念
5楼-- · 2019-01-02 17:55

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;
}
查看更多
登录 后发表回答