Download NumberToWord.zip – 78.64 KB
Download NumberToWord – Java (Thanks to Mike)
Introduction
In this article I will talk about converting Numbers to written words in English & Arabic (Tafqeet as pronounced in Arabic).
Background
I was in the middle of programming my project when I needed a code to convert a number to written text.
Our project is mulltilingual, so I needed two versions: one for English and one for Arabic.
I googled “Number to Text” or “Number to Word” and I found a lot of code to convert number to written words for English language and many of them worked fine.
I also found code to convert number to words for Arabic language but unfortunately many of them didn’t work as expected!
So I have decided to go the long way to build a class to do the conversion to Arabic & added also English language support.
Here is a screen shot of a test project that uses the class:
Using the code
I have to mention that I used a code written by Justin Rogers from this link as a start:http://weblogs.asp.net/justin_rogers/articles/151757.aspx
This article contains a code that do a good convert for a decimal value into its equivalent English words, but numbers from my application were actually money amounts, so I needed to add currency names to it ( our project is also multinational, so I had to build the string dynamically from the country’s currency).
This was the easy part after I made a few small changes to Justin’s code to fulfill my English-Number-To-Words requirements.
Now comes the complicated part: converting Numbers to written words in Arabic language!
Arabic language is very complicated, and when it comes to converting it to words I think it is the most difficult language because it has so many rules that depend on the “number” state and the “counted” state.
For example:
The number one & two matches the counted in its feminine state, where the numbers from 3 to 10 are contrary to the counted … etc.
So I have used one method to determine a digit feminine status using its group level & Currency Name Feminine field status, here is the method:
private string GetDigitFeminineStatus(int digit, int groupLevel)
{
if (groupLevel == -1)
{ // if it is in the decimal part
if (Currency.IsCurrencyPartNameFeminine)
return arabicFeminineOnes[digit]; // use feminine field
else
return arabicOnes[digit];
}
else
if (groupLevel == 0)
{
if (Currency.IsCurrencyNameFeminine)
return arabicFeminineOnes[digit];// use feminine field
else
return arabicOnes[digit];
}
else
return arabicOnes[digit];
}
The whole convert process depends on dividing the number into Group Levels, each group contains 3 digits & these levels are numbered as in this example:
Number: 987,654,321.345
345: Group Level -1
321: Group Level 0
654: Group Level 1
987: Group Level 2
this is accomplished by this code:
Byte group = 0;
while (tempNumber >= 1)
{
// seperate number into groups
int numberToProcess = (int)(tempNumber % 1000);
tempNumber = tempNumber / 1000;
// convert group into its text
string groupDescription = ProcessArabicGroup(numberToProcess, group, Math.Floor(tempNumber));
group++;
}
Then we have to process each group & convert it to its text depending on its group level.
Inside the ProcesArabicGroup Method, we check for the special case for 200 as it has its special rule in Arabic:
if (hundreds > 0)
{
if (tens == 0 && hundreds == 2) // حالة المضاف
retVal = String.Format(“{0}”, arabicAppendedTwos[0]);
else // الحالة العادية
retVal = String.Format(“{0}”, arabicHundreds[hundreds]);
}
Also the number 2 has another special rule which is dicussed by this code:
if (tens == 2 && hundreds == 0 && groupLevel > 0)
{ // This is special case for number 2 when it comes alone in the group
if (_intergerValue == 2000 || _intergerValue == 2000000 || _intergerValue == 2000000000 || _intergerValue == 2000000000000 || _intergerValue == 2000000000000000 || _intergerValue == 2000000000000000000)
retVal = String.Format(“{0}”, arabicAppendedTwos[groupLevel]); // في حالة الاضافة
else
retVal = String.Format(“{0}”, arabicTwos[groupLevel]);// في حالة الافراد
}
For group numbers over 20, it is considered as complicated of 2 digits so each one will get its own converted text.
int ones = tens % 10;
tens = (tens / 10) – 2; // 20’s offset
if (ones > 0)
{
if (retVal != String.Empty)
retVal += ” و “;
// Get Feminine status for this digit
retVal += GetDigitFeminineStatus(ones, groupLevel);
}
if (retVal != String.Empty)
retVal += ” و “;
// Get Tens text
retVal += arabicTens[tens];
Also Arabic language is sensitive to currency names which also depends on the number state so I had to add four different names for the same currency name to support all states, There fields are used at the end of the method when constructing the final String:
if (_intergerValue != 0)
{ // here we add currency name depending on _intergerValue : 1 ,2 , 3—>10 , 11—>99
int remaining100 = (int)(_intergerValue % 100);
if (remaining100 == 0)
formattedNumber += Currency.Arabic1CurrencyName;
else
if (remaining100 == 1)
formattedNumber += Currency.Arabic1CurrencyName;
else
if (remaining100 == 2)
{
if (_intergerValue == 2)
formattedNumber += Currency.Arabic2CurrencyName;
else
formattedNumber += Currency.Arabic1CurrencyName;
}
else
if (remaining100 >= 3 && remaining100 <= 10)
formattedNumber += Currency.Arabic310CurrencyName;
else
if (remaining100 >= 11 && remaining100 <= 99)
formattedNumber += Currency.Arabic1199CurrencyName;
I have created one class to simplify the process, it is called: CurrencyInfo which contains the definition for Currency object, it has the following properties:
CurrencyID = 0; |
Just ID |
CurrencyCode = “SYP”; |
Its Code |
IsCurrencyNameFeminine = true; |
Is the currency name feminine or no? |
EnglishCurrencyName = “Syrian Pound”; |
Like: one Syrian Pound |
EnglishPluralCurrencyName = “Syrian Pounds”; |
Like: thirty four Syrian Pounds |
EnglishCurrencyPartName = “Piaster”; |
For the decimal part |
EnglishPluralCurrencyPartName = “Piasteres”; |
For the decimal part |
Arabic1CurrencyName = “ليرةسورية“; |
For the number one in Arabic |
Arabic2CurrencyName = “ليرتانسوريتان“; |
For the number two in Arabic |
Arabic310CurrencyName = “ليراتسورية“; |
For numbers between 3 and 10 in Arabic |
Arabic1199CurrencyName = “ليرةسورية“; |
For numbers above 11 in Arabic |
Arabic1CurrencyPartName = “قرش“; |
For the decimal part in Arabic |
Arabic2CurrencyPartName = “قرشان“; |
For the decimal part in Arabic |
Arabic310CurrencyPartName = “قروش“; |
For the decimal part in Arabic |
Arabic1199CurrencyPartName = “قرشاً“; |
For the decimal part in Arabic |
PartPrecision = 2; |
Part precision, like: 1 Syrian Pound = 100 Piasters ( 2 is number of Zeros) |
IsCurrencyPartNameFeminine |
Is the currency part name feminine or no? |
As you can see from the table, it is very easy to setup any other currency by filling the specified fields.
Points of Interest
I hope this was helpful to you.
Please feel free to correct/suggest any modifications to the code.
Oh man you remind me of Algorithms I & II days for Yahia Najjar 🙂
Anyway your Code looks brilliant though I’m in a different career path than programming but it’s very nice to look into codes from time to time.
Hi Besher.
Thanks for your comment.
Yes I remember Yahia Najjar 😉 & I love Algorithms & for that I am still a programmer 🙂
Hi,
I am not a programmer but i need NumberToWord ready to use as an exe file sadly i could not find it !?
any help ? please…
email: tenderson@hotmail.com
Thank you.
Hi,
If you download the zip file attached to the article, you can find the exe for the test project in this sub-folder: NumberToWord\bin\Debug
Please let me know if you need anything else.
Best Regards,
Thank you Adel,
It works ! my problem was .NET Framework was missing, now after testing it as it is i noticed that it writes for exmp. ( فقط ) in the begining and ( إماراتياً لا غير ) because my goal is to use it filling and printing checks i really could use the following example (One Thousand Five Hundred Dirhams without UAE only… of course the equivalent in Arabic. Since i wish to use it for Moroccan banks checks any possibility for French-Arabic version..!? i hope you could help in this one.
Arabic is very proud of you just as we are proud of it.
keep on the good work Adel.
Thanks and Best Regards.
Hi.
I have updated the exe file to reflect what you asked for.
Here is the link for the updated file: https://www.sugarsync.com/pf/D6711688_97_979603802
For the French-Arabic version: Unfortunately, I don’t know French Language but I have this file in english: https://www.sugarsync.com/pf/D6711688_97_979613501
if you can translate this file into its related french words, I will include french version in the app.
Best Regards.
Hi,
I checked the updated file you mentioned but unfortunately is still displaying ( فقط ) in the begining and ( لا غير ) in the end of arabic result, any purpose of that extras?
I changed the basic English numbers-text to French i hope it helps.
It seems like i need an e-mail address to send you the modified text file since i can’t send an attachement through the blog.
By the way here is the name of an openoffice add-on (numbertext-0.9.4) which does similar job but arabic is missing and there is a mistake in French! example: 1111= (onze cent onze) but i think this is right one (mille cent onze).
Best Regards.
Hi,
You can use this e-mail: adel@khayata.com
Once you send me the translation, I will update all your requests with one exe file.
Best Regards,
Hi Adel,
I was looking for code that can convert numbers to arabic and i stumbled upon your C# source. I migrated your code into java and it works perfectly (syntax is the only difference).
Also with regards to the printing in the wrong order, I debug the code and it was not the problem of your program. When i printed the translated text using System.out.println(), it printed in the reverse order meaning right-to-left (as mentioned on the above post) but when i debug your code, it was appending the arabic characters in the correct order.
What i did was i copied the text that was printed and pasted it as an email subject (outlook does good job in arabic), and it was pasted in the correct order.
Anyways, I installed arabic language and arabic keyboard in Windows 7 and run it again in Eclipse and it was printing now in the correct order.
Many thanks to your code, I believe I need to send back the equivalent java source to you. How can i send it to you?
Thanks!
Mike
Hi Mike,
I am glad this code helped you out.
I will be more than happy to receive your java code, & if you authorize me, I can add it to the article so people can use it.
Thanks.
Adel
Yes please do share the source. It is still your program, I just migrated it to java. =)
You can send it to adel@khayata.com
sent.
many thanks again.