【问题标题】:Code Golf: Number to Words代码高尔夫:数字到单词
【发布时间】:2010-09-23 12:26:56
【问题描述】:

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

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

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

当前指南:

  • 欢迎以任何编程语言提交(我向 PhiLho 最初对此缺乏明确性)
  • 最大输入为 2^64(字词见以下链接,感谢 mmeyers)
  • Short scale 首选英文输出,但欢迎使用任何算法。只需在编程语言中评论所使用的方法即可。

【问题讨论】:

  • 是否要考虑en.wikipedia.org/wiki/Long_and_short_scales之类的本地化问题?
  • 如果你这样做,可以加分,但我的初衷是小规模。
  • 我假设输出文本必须是英文;-)。
  • 也许这应该计算输入字符的数量而不是行数?许多语言允许每行多个步骤,而其他语言则不允许。

标签: language-agnostic nlp code-golf rosetta-stone


【解决方案1】:

A86 assember - 汇编成一个 .COM 可执行文件:

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

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

这是(稍微小一点的)代码。由于 A86 是仅 8086 的汇编器,因此我不得不手动编写 32 位扩展代码:

    mov di,strings
    mov dx,tree_data * 8 + 1
    mov bp,code_data * 8
l1:
    mov ch,8
    call extract_bits
    xchg dx,bp
    call extract_bit
    xchg dx,bp
    jnc l2
    add dx,ax
l2:
    call extract_bit
    jc l3
    mov ch,6
    call extract_bits
    shr al,2
    cmp al,11
    push l27
    jl get_string
l25:
    add al,48+32
    stosb
l27:
    mov dx,tree_data * 8 + 1
l3:
    cmp bp,end_data * 8
    jl l1

convert:
    mov bx,'01'
    mov di,01000h
    push di

    mov al,[80h]
    mov ah,ch
    mov bp,ax
    add bp,81h
    cmp al,2
    jl zero
    jg l90
    cmp byte ptr [82h],bh
    jne l90
zero:   
    mov al,39
    push done

get_string:
    mov si,strings-1
    or al,al
    je l36
l35:
    inc si
    cmp byte ptr [si],';'+32
    jne l35
    dec al
    jnz l35
l36:
    inc si
l37:
    lodsb
    cmp al,';'+32
    je ret
    stosb
    jmp l37


l90:
    inc ax
    mov dh,3
    div dh
    add al,28
    mov dl,al
    add ah,80h
    db 0fh, 0b6h, 0f4h ; movzx si,ah
    mov word ptr [80h],'00'

l95:    
    lodsb

    sub al,bh
    jle l100
    call get_string2
    mov al,29
    call get_string2

l100:
    lodsw
    push ax
    cmp al,bl
    jl l150
    jg l140
    cmp ah,bh
    je l140

    mov al,ah
    sub al,'0'-10
    push l150

get_string2:
    push si
    call get_string
    pop si
    mov al,' '
    stosb
    ret

l140:
    sub al,'0'-19
    call get_string2

l150:
    pop ax
    cmp ah,bh
    jle l200
    cmp al,bl
    je l200
    mov al,ah
    sub al,bh
    call get_string2

l200:
    cmp dl,29
    jle l300

    mov al,[si-3]
    or al,[si-2]
    or al,[si-1]
    cmp al,bh
    je l300

    mov al,dl
    call get_string2

l300:
    dec dl
    cmp si,bp
    jl l95

done:   
    mov byte ptr [di],'$'
    pop dx
    mov ah,9
    int 21h 
    int 20h

l41:
    rcr al,1
    dec ch
    jz ret

extract_bits:
    push l41
extract_bit:
    mov si,dx
    shr si,3
    mov bh,[si]
    mov cl,dl
    and cl,7
    inc cl
    ror bh,cl
    inc dx
    ret

tree_data:
    dw 01e8fh, 01e58h, 05ea8h, 0303ch, 0652ah, 0df6fh, 0e03ch, 078bdh
    dw 07500h, 05e02h, 0603ch, 01ec1h, 0793dh, 07d40h, 08080h, 0603ch
    dw 02838h, 09f6fh, 07a3dh, 040f1h, 07a22h, 080f1h, 07264h, 0403dh
    dw 0dee1h, 0793ch, 040f1h, 01407h, 07d32h, 01e2fh, 08948h
    db 048h
code_data:
    dw 052fh, 0c43bh, 09ba7h, 057afh, 06ca2h, 0297bh, 0abeh, 09e3h
    dw 0ab46h, 0f902h, 03eb8h, 021e1h, 09e7ch, 077dh, 0b59ah, 0f82ah
    dw 0f354h, 0be2ah, 0cdfah, 06534h, 0978ah, 02b4ch, 0ced3h, 0c7c8h
    dw 03335h, 0bcc8h, 04f82h, 07f15h, 0eaf8h, 0ff7h, 0df65h, 0143fh
    dw 07f2fh, 0fd68h, 0fda1h, 0e687h, 0e0c3h, 0d50fh, 074c6h, 0f135h
    dw 05b75h, 08c33h, 08589h, 048ceh, 06fe7h, 06967h, 0d387h, 02cedh
    dw 0c7adh, 08c77h, 08e92h, 0e2d1h, 0f677h, 077e8h, 0ba1ah
    db 01bh
end_data:

strings:

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

【讨论】:

    【解决方案2】:

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

    convert_number(2850)
    

    返回

    20850

    如果你想要一个更棒的处理逗号和数字的工具,请查看 zac hesters 的工作 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;
    }
    

    【讨论】:

      【解决方案3】:

      几年前,我用 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);
              }
          }
      }
      

      这个是给土耳其莱拉(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);
      

      【讨论】:

        【解决方案4】:

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

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

        输出:

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

        【讨论】:

        • 为什么是十进制?它是否支持像 12345.789 这样的数字?
        • 因为十进制类型是一个 128 位数字,这意味着无论“十进制”精度如何,它都是巨大的。他只是想用一个巨大的数字来试一试。
        • 你确定不是“sextillion”吗?你目前有“sexillion”。
        • @Maxim Z. - 谢谢,我已经修好了。
        • 如果您使用递归,您可以将其缩短一行。
        【解决方案5】:

        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 二 一千二十四 一百万、四万八千、五百七十六

        【讨论】:

          【解决方案6】:

          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++ 呢?这是代码高尔夫 - 使用最好的“俱乐部”!
          • 杰森桑德拉姆,我不同意。用您的语言打高尔夫球。嫉妒那些有不同障碍的人(也就是任何使用 Lisp 的人)。
          【解决方案7】:

          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

          【讨论】:

            【解决方案8】:

            查看递归的更好答案。好多了。

            疯狂的道具Darius 以获得灵感。你的 big-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 当前解决方案的调整,这反过来又是对我的旧解决方案的调整,这是受他的启发,他在 cmets 中给出了一些错误提示。这也是对 Python 的犯罪。

            以下剧透,rot13'd 为您提供保护,因为高尔夫乐趣的一半 弄清楚如何。我强烈推荐mnenhy Firefox 扩展来解码这个(和其他简单的编码方案)内联。

            Pbafgnagf (Veranzrq 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。 avf 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']]

            【讨论】:

            • 酷。 :) 乍一看我根本不明白,但是您可以通过删除空格(第 1 行、第 3 行和最后一行)和第 1 行上的“!= 0”来减少 7 个字节。
            • 错误:g(19) 是“九”。将s的定义中的“n
            • 太棒了!而且我太累了,无法再弄清楚了——我确实看到前三行中挤出了 4 个字节: g=lambda n:["zero"," ".join(w(n,0))] [n>0] w=lambda n,l:e if n0]
            • 2**64 不需要sextillion;删除它使我们减少到 480 字节,我正在将它打包。这很有趣,以一种毫无意义的方式。 :)
            • 我在睡觉前回到了这个(这个代码高尔夫的东西应该带有警告)——发现它的可读性令人惊讶。随着理解,还有一种方法可以将其减少到 473 个字节: w=lambda n,l:e if n0]+s(n%d)+(e,k[l])[n%m>0]
            【解决方案9】:

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

            【讨论】:

            • 令人印象深刻。 :) 我还没有读过,但是第二行末尾的 \ 不是可删除的吗?
            • 噢!它是!再下一个字节,还有 423 个。谢谢。
            • 还有 5 个字节,我无法阻止自己。我知道那里的某个地方还有一些臃肿......
            • 如果您压缩更多字节,您可以将其放在评论中;-)
            • 你在开玩笑吗?我不知道 Python 代码看起来这么性感!
            【解决方案10】:
            #!/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";
            

            【讨论】:

              【解决方案11】:

              是否有人计划尽快添加适当的逗号和“和”?还是从 21 到 99 连字?否则没什么意义,恕我直言:)

              '九十九万九千九十九'

              ‘九十九万九千九十九’

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

              【讨论】:

              • “and”的用法不正确,但我认为连字符是合法的。
              • 连字符是必需的,不仅仅是合法的,逗号也是如此。我也希望对“和”有所不同,但我觉得这是英国与美国的事情。
              • 在美国,您通常只会在序列的末尾听到“and”。 “和”在美国肯定被认为是错误的。使用时,表示数字的小数部分。所以“九百九十九”在技术上意味着 900.99,尽管大多数人会读作 999。
              • 我刚刚查看了维基百科,您对英国与美国的“和”不同是正确的。这是一个链接:en.wikipedia.org/wiki/Names_of_numbers_in_English 这也表明美国和英国都需要连字符。
              • "and" 在澳大利亚使用,并且 (fyi) 在 Project Euler 问题 #17 中需要:projecteuler.net/index.php?section=problems&id=17
              【解决方案12】:

              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 为起点。
              • strictwarnings 下工作。

              【讨论】:

                【解决方案13】:

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

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

                我不得不提一下,我在 BATCH 中解决这个问题很有趣。 :)

                【讨论】:

                • 天哪,太神奇了。让我想起了 90 年代初我工作中的数千行 DOS 批处理文件的不那么美好的回忆。
                • 嘿,谢谢。我其实很喜欢 BATCH。在 BATCH 中解决那些“代码高尔夫”问题很有趣。 :)
                • 天哪。 +1 表示我没有的耐心。
                • 这很恶心但很有趣,所以我给了你 +1。除非您真的想...
                • 是的,我从来没有使用批处理-我只是喜欢它,所以我用它来解决代码高尔夫问题... ;) 感谢您的投票, 顺便提一句。 :)
                【解决方案14】:

                Python,446 字节。 80列以下的所有行,该死的。这是Paul Fisher's solution,几乎每一行都有编码调整,低于他的 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(仍然没有获胜)。我尝试用一​​种新算法重新开始,但它无法击败 Fisher 的算法。最后,这是他的代码的调整。尊重!

                混淆代码已针对干净代码进行了测试,该代码已通过大量案例进行了眼球检查。

                【讨论】:

                • 将数字 100 替换为常数会更令人头疼——呃,更短的代码。
                • 天啊!在我从头开始重新尝试我没有发布的那件事之后,我错过了这一点,真是太愚蠢了。你赢了!
                【解决方案15】:

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

                对象数字拼写器 { val 数字 = Array("","一","二","三","四","五","六","七","八","九") val teens = Array(“十”、“十一”、“十二”、“十三”、“十四”、“十五”、“十六”、“十七”、“十八”、“十九”) val tens = Array("", “十”, “二十”, “三十”, “四十”, “五十”, “六十”, “七十”, “八十”, “九十”) val数千=数组(“”,“千”,“百万”,“十亿”,“万亿”,“万亿”,“五亿”) def spellGroup(num:Int) = { val (v3, v2, v1) = ((num / 100) % 10, (num / 10) % 10, num % 10) val hs = v3 匹配 { case 0 => "";案例 d => 数字(d)+“百”} val ts = v2 匹配 { 案例 0 => 数字(v1) 案例 1 => 青少年(v1) case _ => v3 match { case 0 => tens(v2); case _ => 十位(v2)+“-”+数字(v1)} } hs + ts } def numberGroups(num:Long) = { def _numberGroups(num:Long, factor:Int):List[(Double,Int)] = 因子匹配 { 案例 0 => 列表((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)) 整数 dropWhile (x => x._1 == 0.0) } def spell(num:Long) = num match { case 0 => "zero"; case _ => (numberGroups(num) map { x => spellGroup(x._1) + " " +数千(x._2) + " " }).mkString.trim } }

                用法是:

                NumSpeller.spell(458582)
                

                【讨论】:

                • 工作不正常:“十八、十九、二十、二十、二十”
                【解决方案16】:

                好的,这里是 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
                

                【讨论】:

                  【解决方案17】:

                  一个 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
                  

                  【讨论】:

                  • 顺便说一句,SQL 不支持无符号数据类型,因此您仅限于 +/- 2^63-1 - 但脚本也表示否定。 :)
                  【解决方案18】:

                  这是一个相对简单的 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;}
                  

                  【讨论】:

                    【解决方案19】:

                    嗯,你可能把标准设置得有点高,无论是在极限(18,446,744,073,709,552,000,我什至不知道怎么写!)和目标(其他代码打高尔夫球导致短代码,这个至少对于数据(单词)来说会很长。

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

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

                    【讨论】:

                      【解决方案20】:

                      Lisp,只使用标准函数:

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

                      奖金:

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

                      【讨论】:

                      • 你错过了“百”和“三十四”之间的“和” :-)
                      • 哦,好的。 OP给出的示例不包括“和”,我看到的任何其他解决方案也没有。英语不是我最擅长的领域,但我相信拼写大数字的正确方法是没有“and”。
                      • 我认为正确的方法是没有 and,除非它们是两个单独的数字(或组合:John 有 2 美元,Jim 有 50 美分,他们有 2 美元和 50 美分)。
                      • AFAIK,“and”更像是英国英语的东西(正确的方式;)。
                      • @OtherMichael 并不是它在两个单独的数字之间分隔, and 代表小数点。 2.3 = 十分之二又十分之三
                      【解决方案21】:

                      这是作弊吗?

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

                      【讨论】:

                      • 您还需要计算您正在使用的库中的行数。
                      • 大声笑绝对作弊! =) 没有什么能在高尔夫上击败 perl 呵呵
                      • 可能是:perl -MNumber::Spell -E"say spell_number 2
                      • 我想知道为什么这个只有 2 票,而 Lisp 版本超过 10?
                      【解决方案22】:

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

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

                      【讨论】:

                      • 您的浮点代码处理价值 0.10 美元的检查的效果如何?
                      猜你喜欢
                      • 1970-01-01
                      • 2010-11-28
                      • 2010-12-17
                      • 2011-01-15
                      • 1970-01-01
                      • 1970-01-01
                      • 2010-12-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多