Friday, November 7, 2008

แปลงตัวเลขเป็นตัวอักษร หรือที่เรียกว่า Number To Words

เหตุที่เขียนบทความนี้ก็เพราะว่าบางครั้งที่ผมจะเขียนตัวเลขแล้วให้มันแปลงเป็นตัวอักษรเพื่อเอาไปพิมพ์เช็ค หรือว่าเราอาจจะแปลงโปรแกรมนี้ให้เป็นโปรแกรมที่อ่านออกเสียงก็ได้เช่น

เวลาเราเช็คเงินบนมือถือของเราครับ

มาดู Code กันเลยดีกว่าว่าเป็นยังไงในที่นี้ผมเขียนทั้งที่เป็นภาษาอังกฤษและที่เป็นภาษาไทย

ในภาษาอังกฤษนั้นเวลาอ่านตัวเลข จะมี one ten hundred thousand million billion และเลขที่ตั้งแต่ 11-19 ที่จะเป็น Eleven, Twelve, Thirteen ... ไปเรื่อยๆ และหลักสิบก็จะเป็น

Twenty , Thirty ไปเรื่อยๆเช่นกัน โดยใน ภาษาอังกฤษ นั้นไม่มีคำเรียกหลักหมื่น และหลักแสน เราจะเรียกเป็น ten thousand และ hundred thousand แทนและมักจะใส่ and ก่อนที่จะถึงตัวเลขสุดท้าย

ซึ่งต่างจากภาษาไทยครับ

แต่ภาษาไทยหากลงท้ายด้วยเลขหนึ่งแล้วมักจะใช้คำว่าเอ็ด เช่น 11 เราเรียกว่าสิบเอ็ดไม่ใช่สิบหนึ่งอซึ่งรายละเอียดตรงนี้ขึ้นอยู่กับว่าเราจะใช้แบบใดครับ ซึ่งบางคนก็เรียตัวเลขนี้ว่า 101 หนึ่งร้อยหนึ่ง บางคนก็เรียกว่า ร้อยเอ็ด

และในภาษาไทยหลัก 20-29 นั้นจะเรียกเป็นยี่ หลักการคล้ายๆกับ ภาษาอังกฤษในหลักสิบ

รายละเอียดว่าทำยังไงไปดูกันที่ Code เลย ครับ

public class NumberToWordsConvertor

{

private const int MAX_DIGIT_ARRAY_TH = 6;//สะหรับภาษาไทยแบ่งกันที่หลักล้าน

private const int MAX_DIGIT_ARRAY = 4;//สำหรับภาษาอังกฤษแบ่ที่หลักพัน

private string[] _smallNumbers = new string[] {"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"};

private string[] _smallNumbersTh = new string[] { "ศูนย์", "หนึ่ง", "สอง", "สาม", "สี่", "ห้า", "หก", "เจ็ด", "แปด", "เก้า"};

private string[] _tens = new string[] { "", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety" };

private string[] _scaleNumbers = new string[] { "", "Thousand", "Million", "Billion" };

private string[] _scaleNumbersTh = new string[] { "","สิบ","ร้อย", "พัน", "หมื่น", "แสน" };

//สำหรับแปลงเป็นภาษาอังกฤษ

public string NumberToWords(int number)

{

// หากเป็น 0 ให้ค่าแรกไปเลย

if (number == 0)

return _smallNumbers[0];

int[] digitGroups = new int[MAX_DIGIT_ARRAY];

// ทำให้เป็นพวกทังหมดก่อนครับ

int positive = Math.Abs(number);

for (int i = 0; i < MAX_DIGIT_ARRAY; i++)

{

digitGroups[i] = positive % 1000;

positive /= 1000;

}

string[] groupText = new string[MAX_DIGIT_ARRAY];

for (int i = 0; i < MAX_DIGIT_ARRAY; i++)

groupText[i] = ThreeDigitGroupToWords(digitGroups[i]);

string combined = groupText[0];

bool appendAnd;

appendAnd = (digitGroups[0] > 0) && (digitGroups[0] < 100);

for (int i = 1; i < MAX_DIGIT_ARRAY; i++)

{

if (digitGroups[i] != 0)

{

string prefix = groupText[i] + " " + _scaleNumbers[i];

if (combined.Length != 0)

prefix += appendAnd ? " and " : ", ";

appendAnd = false;

combined = prefix + combined;

}

}

if (number < 0)

combined = "Negative " + combined;

return combined;

}

// สำหรับภาษาไทย

public string NumberToWordsTh(int number) {

string combined = "";

int newnumber = 0;

if (number == 0)

return _smallNumbersTh[0];

int[] digitGroups = new int[MAX_DIGIT_ARRAY_TH];

int positive = Math.Abs(number);

if (positive > 999999)

{

newnumber = positive / 1000000;

positive = positive % 1000000;

}

for (int i = 0; i < MAX_DIGIT_ARRAY_TH; i++)

{

digitGroups[i] = positive % 10;

positive /= 10;

}

string[] groupText = new string[MAX_DIGIT_ARRAY_TH];

for (int i = 0; i < MAX_DIGIT_ARRAY_TH; i++)

{

if (digitGroups[i] > 0)

{

if (digitGroups[i] == 1 && i == 0 && digitGroups[i+1]>0)

{

groupText[i] = "เอ็ด";

}else if ((digitGroups[i] == 2 && i == 1))

{

groupText[i] = "ยี่";

}else if (!(digitGroups[i] == 1 && i == 1)) {

groupText[i] = _smallNumbersTh[digitGroups[i]];

}

}

}

combined += groupText[0];

for (int i = 1; i < MAX_DIGIT_ARRAY_TH; i++)

{

if (digitGroups[i] != 0)

{

string prefix = groupText[i] + _scaleNumbersTh[i];

combined = prefix + combined;

}

}

if (newnumber > 0) {

combined = NumberToWordsTh(newnumber) + "ล้าน" + combined;

}

if (number < 0)

combined = "ลบ " + combined;

return combined;

}

// ตรงนี้ใช้กับ ภาษาอังกฤษอย่างเดียวครับ

private string ThreeDigitGroupToWords(int threeDigits)

{

string groupText = "";

int hundreds = threeDigits / 100;

int tensUnits = threeDigits % 100;

if (hundreds != 0)

{

groupText += _smallNumbers[hundreds] + " Hundred";

if (tensUnits != 0)

groupText += " and ";

}

int tens = tensUnits / 10;

int units = tensUnits % 10;

if (tens >= 2)

{

groupText += _tens[tens];

if (units != 0)

groupText += " " + _smallNumbers[units];

}

else if (tensUnits != 0)

groupText += _smallNumbers[tensUnits];

return groupText;

}

}

หลังจากนั้นเวลาเรียกใช้ก็

int number = 2147483647;

NumberToWordsConvertor convertor = new NumberToWordsConvertor()

String resultEng = convertor.NumberToWords(number).ToUpper();

String resultTh = convertor. NumberToWordsTh (number);

จะได้ผลออกมาดังนี้ครับ

TWO BILLION, ONE HUNDRED AND FORTY SEVEN MILLION, FOUR HUNDRED AND EIGHTY THREE THOUSAND, SIX HUNDRED AND FORTY SEVEN

สองพันหนึ่งร้อยสี่สิบเจ็ดล้านสี่แสนแปดหมื่นสามพันหกร้อยสี่สิบเจ็ด

ในที่นี้เราใช้ตัวแปรประเภท int ใน C# จัมีค่ามากที่สุดคือ 2147483647 ฉนั้นหากตัวเลขมากกว่านี้แล้วจะทำให้ผลออกมาไม่ถูกต้องครับ

ผมคิดว่าแค่นี้ก็น่าจะพอนำไปใช้ได้แล้ว หากอยากจะให้มีอะไรเพิ่มเติมเช่นให้มีคำว่าบาทหรือว่ามี $ หรือว่ามีจุดทศนิยม เราก็สามารถไปเขียนเองได้ในภายหลังไม่ยากเลยใช่ไหมละครับ

1 comment:

tiantavat said...

ถ้าเปลี่ยน type จาก int เป็น double จะรับค่าได้มากขึ้นไหมคับ