The Pragmatic Programmer

Tulisan iseng kalo ada waktu.
See also: Other Geeks@INDC

Number Pronouncer

Lagi megang modul finance, ada kebutuhan untuk bikin penterjemah angka menjadi terbilang dalam Bahasa Indonesia. Codenya masih butuh refactoring kalo gw sempat nanti gw beresin. Berikut code lengkapnya:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Class1
    {
        private string[] _ZeroToEleven = {"Nol", "Satu", "Dua", "Tiga", "Empat"
                                        , "Lima", "Enam", "Tujuh", "Delapan"
                                        , "Sembilan", "Sepuluh", "Sebelas"};
        private string[] _GroupSuffix = {"", "ribu", "juta", "milyar", "trilyun", "bilyun", "tetra bilyun"};

        public string Pronounce(long Number, bool LowerCase)
        {
            string numberString = Number.ToString();
            string result = string.Empty;

            if (Number <= 11)
            {
                return (LowerCase ? _ZeroToEleven[Number].ToLower() : _ZeroToEleven[Number]);
            }

            //handle puluhan and belasan but starts from twelve up
            if (numberString.Length == 2)
            {
                int firstDigit = Convert.ToInt32(numberString[0].ToString());
                int secondDigit = Convert.ToInt32(numberString[1].ToString());
                //belasan (12 - 19)
                if (firstDigit == 1)
                {
                    return Pronounce(secondDigit, LowerCase) +" belas";
                }
                if (secondDigit == 0)
                {
                    return Pronounce(firstDigit, LowerCase) + " puluh";
                }
                else
                {
                    return Pronounce(firstDigit, LowerCase) + " puluh " + Pronounce(secondDigit, true);
                }
            }

            //handle 100 - 999
            if (numberString.Length == 3)
            {
                long firstDigit = Convert.ToInt32(numberString[0].ToString());
                string lastTwoDigits = numberString.Substring(1);
                long lastTwoDigitNumber = Convert.ToInt64(lastTwoDigits);
                if (firstDigit == 1)
                {
                    if (lastTwoDigitNumber > 0)
                    {
                        result = "Seratus " + Pronounce(lastTwoDigitNumber, true);
                    }
                    else
                    {
                        result = "Seratus";
                    }
                    if (LowerCase)
                    {                       
                        result = result[0].ToString().ToLower() + result.Substring(1);
                    }

                    return result;
                }
                else
                {
                    if (lastTwoDigitNumber > 0)
                    {
                        return Pronounce(firstDigit, LowerCase) + " ratus " + Pronounce(lastTwoDigitNumber, true);
                    }
                    else
                    {
                        return Pronounce(firstDigit, LowerCase) + " ratus";
                    }
                }
            }

            Stack<string> groupStack = GroupNumber(numberString);           
            if(groupStack.Count > _GroupSuffix.Length)
            {
                throw new InvalidOperationException("Number is too big. I don't know how to pronounce it in Bahasa.");
            }
            while (groupStack.Count > 0)
            {
                string currentGroup = groupStack.Pop();
                long currentGroupNumber = Convert.ToInt64(currentGroup);
                //Print only 1000 down with 'se' e.g. Seribu
                if (currentGroupNumber == 1 && groupStack.Count <= 1)
                {
                    if (result.Length > 0)
                    {
                        result += " ";
                    }
                    result += "se" + _GroupSuffix[groupStack.Count];
                }
                else
                {                   
                    if (currentGroupNumber > 0)
                    {
                        if (result.Length > 0)
                        {
                            result += " ";
                        }
                        result += Pronounce(currentGroupNumber, true) + " " + _GroupSuffix[groupStack.Count];
                    }
                }

            }

            result = result[0].ToString().ToUpper() + result.Substring(1);
           
            return result;
        }

        private Stack<string> GroupNumber(string NumberString)
        {
            Stack<string> groupStack = new Stack<string>();
            string currentGroup = string.Empty;

            int counter = 0;
            for (int i = NumberString.Length - 1; i >= 0; i--)
            {
                currentGroup = NumberStringIdea.ToString() + currentGroup;
                counter++;
                if (counter == 3)
                {
                    groupStack.Push(currentGroup);
                    counter = 0;
                    currentGroup = string.Empty;
                }
            }

            if (counter > 0)
            {
                groupStack.Push(currentGroup);
            }

            return groupStack;
        }
    }
}
 

Buat yang butuh silahkan pakai. Kalau ada bug please kasih tahu yaah...!. 

Share this post: | | | |

Comments

cahnom said:

Panjang amat mas kode-nya? Saya pernah posting kode yang lebih sederhana dalam dua bahasa C# dan C++. Silakan lihat di http://semarang.netindonesia.net/blogs/cahnom/archive/2006/05/29/terbilang-cpp.aspx dan http://semarang.netindonesia.net/blogs/cahnom/archive/2006/05/04/terbilang.aspx

# May 10, 2007 9:28 AM

irwansyah said:

Wah...Dalam 2 bahasa...C# dan C++ lagiii...wuih hebat!!!! Tapi bisa handle angka 0 gak yah?

Code yang gw buat sudah dioptimasi maksimal tanpa mengorbankan maintainability. Coba dicompare dengan punya anda. Tapi yah...kalau code boleh nyontek dari orang lain emang gampang...gak perlu mikirin macem-macem :P

Hati-hati bahaya ujub!!!!

# May 10, 2007 9:55 PM

cahnom said:

Kalo pengen handle angka 0 ya tinggal tambahkan satu fungsi

public string NolTerbilang(long x) {

   if (x==0) {

      return "Nol";

   } else {

      return Terbilang(x);

   }

}

Bukan masalah contek menyontek, yang penting dicantumkan sumbernya. Di .NET Framework 2.0 sendiri untuk library kompresi ada yang menyontek algoritma GNU Zip. Selama sumbernya mempublikasikan algoritma dan tidak melarang untuk dicontek ya gak masalah.

Ini hasil pengujian algoritma saya dengan algoritma Mas Irwansyah dengan memasukkan angka 1262728232628 sebagai masukan:

Data ini diambil dari trace information pada aplikasi ASP.NET 2.0.

Terbilang NolTerbilang Begin Proces 0,0019387938969897 0,001156

Terbilang NolTerbilang End Proces 0,00406839416741513 0,002130

Terbilang Pronounce Begin Proces 0,00411951798343086 0,000051

Terbilang Pronounce End Proces 0,0255166508592573 0,021397

Kesimpulannya, algoritma saya (0,002130s) 10x lebih cepat dari algoritma mas Irwansyah (0,021397)

# May 12, 2007 9:21 PM

irwansyah said:

Berikut adalah hasil test case untuk code saya dan code Suyanto <yanto [at] ugm dot ac dot id> yang anda akui sebagai algoritma anda :P. Yang atas adalah output dari code anda yang bawah saya punya. Bisa terlihat bahwa output dari code anda selalu didahului spasi dan tidak cantik :P. Pada test case untuk angka 0 dan lebih dari trilyunan code anda fail!! Untuk test case 0120193289912839 code anda kelebihan spasi, coba lihat dibawah ini:

"seratus dua puluh  trilyun seratus ..."

"Seratus dua puluh trilyun seratus ..."

So, menurut saya code anda belum menghasilkan output yang benar sehingga belum dapat dibandingkan secara performance dengan code saya. Tolong perbaiki dahulu sampai bisa lulus test case di bawah ini baru kita profile. OK??

-------------------------------------------------------

10 =  sepuluh

10 = Sepuluh

100 =  seratus

100 = Seratus

1000 =  seribu

1000 = Seribu

000 =  

000 = Nol

0 =  

0 = Nol

12345 =  dua belas ribu tiga ratus empat puluh lima

12345 = Dua belas ribu tiga ratus empat puluh lima

1345 =  seribu tiga ratus empat puluh lima

1345 = Seribu tiga ratus empat puluh lima

105 =  seratus lima

105 = Seratus lima

1121323 =  satu juta seratus dua puluh satu ribu tiga ratus dua puluh tiga

1121323 = Satu juta seratus dua puluh satu ribu tiga ratus dua puluh tiga

1212 =  seribu dua ratus dua belas

1212 = Seribu dua ratus dua belas

0923890 =  sembilan ratus dua puluh tiga ribu delapan ratus sembilan puluh

0923890 = Sembilan ratus dua puluh tiga ribu delapan ratus sembilan puluh

0120193289912839 =  seratus dua puluh  trilyun seratus sembilan puluh tiga milyar dua ratus delapan puluh sembilan juta sembilan ratus dua belas ribu delapan

ratus tiga puluh sembilan

0120193289912839 = Seratus dua puluh trilyun seratus sembilan puluh tiga milyar dua ratus delapan puluh sembilan juta sembilan ratus dua belas ribu delapan

ratus tiga puluh sembilan

1238190381902380912 =

1238190381902380912 = Satu tetra bilyun dua ratus tiga puluh delapan bilyun seratus sembilan puluh trilyun tiga ratus delapan puluh satu milyar sembilan

ratus dua juta tiga ratus delapan puluh ribu sembilan ratus dua belas

9012301273827001928 =

9012301273827001928 = Sembilan tetra bilyun dua belas bilyun tiga ratus satu trilyun dua ratus tujuh puluh tiga milyar delapan ratus dua puluh tujuh juta

seribu sembilan ratus dua puluh delapan

1010101010101010101 =

1010101010101010101 = Satu tetra bilyun sepuluh bilyun seratus satu trilyun sepuluh milyar seratus satu juta sepuluh ribu seratus satu

101 =  seratus satu

101 = Seratus satu

200 =  dua ratus

200 = Dua ratus

50 =  lima puluh

50 = Lima puluh

51 =  lima puluh satu

51 = Lima puluh satu

1011234512345 =  satu trilyun sebelas milyar dua ratus tiga puluh empat juta lima ratus dua belas ribu tiga ratus empat puluh lima

1011234512345 = Satu trilyun sebelas milyar dua ratus tiga puluh empat juta lima ratus dua belas ribu tiga ratus empat puluh lima

# May 14, 2007 9:43 PM

norman said:

Wah, Wan.. case yg kamu show trivial.

Mengubah karakter pertama jd Upper Case, dan remove spasi, dan menambahkan ke 10^x yg lebih tinggi dpt di add ke code si cahnom. My guess it won't really hurt the performance. Kalaupun mau di profile lagi, meski jd lebih lambat, tetap saja akan lebih cepat dari code kamu. Karena skrg aja 10x faster!

Besides, cahnom code looks better. "Elegant" gitu loh... :)

Anyway...

# May 25, 2007 9:52 AM

irwansyah said:

Buktikan dulu :)

# June 1, 2007 8:38 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 
Are you human?:  


Enter the numbers above: