ผู้เขียน หัวข้อ: [VB.Net] การแปลงตัวเลขจำนวนเงินเป็นภาษาไทย ระดับหลักเก้าล้านล้านบาท  (อ่าน 211 ครั้ง)

ออฟไลน์ ทองก้อน ทับทิมกรอบ

  • Administrator
  • *****
  • กระทู้: 245
  • เพศ: ชาย
  • Webmaster G2GNet
[VB.Net] การแปลงตัวเลขจำนวนเงินเป็นภาษาไทย ระดับหลักเก้าล้านล้านบาท



โจทย์ข้อนี้คิดให้ยากมันก็ยาก แต่หากคิดให้ง่ายมันก็ง่าย เพราะเราจะแยกคิดกรณีเลขจำนวนเต็มซ่ะก่อน ซึ่งเอาแค่ 3 หลัก คือไปถึงหลักร้อยก็เพียงพอ เพราะอะไร??? ... ตัวที่มีปัญหามันคือหลักสิบกับหลักหน่วย ซึ่งจะมีดังต่อไปนี้คือ

- หนึ่งสิบ และ สองสิบ (พวกสามสิบไปถึงเก้าสิบไม่มีปัญหา) ... การแก้โจทย์ก็แค่สั่งแทนที่ค่า (Replace) เจ้า 2 ค่านี้ก็พอคือ หนึ่งสิบ = สิบ และ สองสิบ = ยี่สิบ

- หนึ่ง, สิบหนึ่ง, สองหนึ่ง, สามหนึ่ง, ... เก้าหนึ่ง ร้อยหนึ่ง พันหนึ่งไปจนถึงแสนหนึ่ง ... การแก้โจทย์ก็แค่เปลี่ยนจาก หนึ่ง = เอ็ด ...

เราลองยกตัวอย่างมาสัก 3 หลักพอ เช่น 321 ... (หรือหาตัวเลขปกติก่อน)
(รอบที่ 1) เราเอาค่าหลักซ้ายมือสุดก็คือ 3 (สมองนึกถึง Mid String Function ทันที คือ Mid("321", 1, 1))
    1.1 หาว่า 3 มันตรงกับภาษาไทยอะไร แน่นอนมันก็คือ "สาม"
    1.2 หาว่าเลขตัวนี้มันอยู่หลักใด แน่นอนมันคือหลัก "ร้อย" (ค่าตอนนี้คือ สามร้อย)
(รอบที่ 2) เราเอาค่าหลักซ้ายมือสุดนับเพิ่มไปอีก 1 ก็คือ 2 (คือ Mid("321", 2, 1))
    2.1 หาว่า 2 มันตรงกับภาษาไทยอะไร แน่นอนมันก็คือ "สอง"
    2.2 หาว่าเลขตัวนี้มันอยู่หลักใด แน่นอนมันคือหลัก "สิบ" (เอาค่ารอบที่ 1 และ 2 มาเรียงต่อกัน ค่าตอนนี้คือ สามร้อยสองสิบ)
(รอบที่ 3) เราเอาค่าหลักซ้ายมือสุดนับเพิ่มไปอีก 1 ก็คือ 1 (ตัวสุดท้าย)
    3.1 หาว่า 1 มันตรงกับภาษาไทยอะไร แน่นอนมันก็คือ "หนึ่ง" Mid("321", 3, 1)
    3.2 หาว่าเลขตัวนี้มันอยู่หลักใด แน่นอนมันคือหลัก "หน่วย" แต่ไม่ต้องใส่หน่วย นั่นคือมันต้องไม่มีอะไรมาต่อท้าย (เอาค่ารอบที่ 1 และ 2 และ 3 มาเรียงต่อกัน ค่าตอนนี้คือ สามร้อยสองสิบหนึ่ง)

>> เปลี่ยน สองสิบ = ยี่สิบ
>> เปลี่ยน ยี่สิบ(หนึ่ง) = ยี่สิบ(เอ็ด)

คำตอบคือ สามร้อยยี่สิบเอ็ด ... ให้สังเกตว่าในแต่ละรอบต้องทำ 2 ครั้ง (นึกถึงการ Loop แล้ว)

เอาใหม่ เช่น 901 ...
(รอบที่ 1) เราเอาค่าหลักซ้ายมือสุดก็คือ 9
    1.1 หาว่า 9 มันตรงกับภาษาไทยอะไร แน่นอนมันก็คือ "เก้า"
    1.2 หาว่าเลขตัวนี้มันอยู่หลักใด แน่นอนมันคือหลัก "ร้อย" (ค่าตอนนี้คือ เก้าร้อย)
(รอบที่ 2) เราเอาค่าหลักซ้ายมือสุดนับเพิ่มไปอีก 1 ก็คือ 0 ... ค่า 0 เราต้องข้ามไปเพราะไม่มีค่า (ค่าตอนนี้คือ เก้าร้อย)
    - สมองนึกถึงคำสั่งเงื่อนไข คือ IF แล้ว คือหากเป็นค่า 0 ไม่ต้องเอามาคิด
(รอบที่ 3) เราเอาค่าหลักซ้ายมือสุดนับเพิ่มไปอีก 1 ก็คือ 1 (ตัวสุดท้าย)
    3.1 หาว่า 1 มันตรงกับภาษาไทยอะไร แน่นอนมันก็คือ "หนึ่ง"
    3.2 หาว่าเลขตัวนี้มันอยู่หลักใด แน่นอนมันคือหลัก "หน่วย" (ค่าตอนนี้คือ เก้าร้อยหนึ่ง)

>> เปลี่ยน หนึ่ง = เอ็ด

คำตอบคือ เก้าร้อยเอ็ด

ข้อคิดพิจารณาในการออกแบบ ...
1.) ข้อย่อยข้อแรก เราต้องเขียนชุดตัวเลข ในการเปรียบเทียบดังนี้
0 = "ศูนย์"
1 = "หนึ่ง"
2 = "สอง"
3 = "สาม"
4 = "สี่"
5 = "ห้า"
6 = "หก"
7 = "เจ็ด"
8 = "แปด"
9 = "เก้า"

2.) ข้อย่อยข้อที่สอง คือ การหาหลัก เราสามารถเขียนแบบ Array (จะใช้ Structure หรือ Enum หรืออะไรก็สุดแล้วแต่ใครจะถนัดในภาษานั้นๆ) ดังนี้
arrUnit(0) = "" <-- ก็หลักหน่วยนั่นเอง
arrUnit(1) = "สิบ"
arrUnit(2) = "ร้อย"
arrUnit(3) = "พัน"
arrUnit(4) = "หมื่น"
arrUnit(5) = "แสน"
arrUnit(6) = "ล้าน"

ค่าที่เพี้ยน เช่น สิบหนึ่ง สามสิบหนึ่ง หรือ หนึ่ง เราจะมาสั่งเปลี่ยนคำทีหลัง ... แค่นี้เองคุณก็จะได้การแปลงจำนวนตัวเลข เป็นภาษาไทยในระดับหลัก "เก้าล้าน" ได้อย่างสบาย แต่ถ้าหากอยากได้ค่ามากกว่านี้ ก็แค่คิดเลขจำนวนเต็มเพิ่มขึ้นมาอีกชุดหนึ่งที่มากกว่าตัวเลข 6 หลัก (แยกคิดทีละชุด หรือจะวนรอบเอาก็ได้ แต่โค้ดที่ผมนำเสนอนี้ผมใช้การแยก เพื่อให้ทุกๆท่านได้มองเห็นภาพออกได้ง่ายๆ) ... คิดได้แบบนี้ก็ หมูน้อยร้องอู๊ดดดดดดดดดดดดดด

มาดูโค้ดกันเถอะ ...
โค๊ด: [Select]
' / ----------------------------------------------------------------------------------------
' / Developer : Mr.Surapon Yodsanga (Thongkorn Tubtimkrob)
' / eMail : thongkorn@hotmail.com
' / URL: http://www.g2gnet.com (Khon Kaen - Thailand)
' / Facebook: www.facebook.com/g2gnet
' / Purpose: Convert numeric to Thai word (Baht+Stang)
' / Microsoft Visual Basic .NET (2010)
' / ----------------------------------------------------------------------------------------
Public Class frmMain

    Private Sub frmMain_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Me.CenterToScreen()
        txtNumber.Text = "365001.23" ' "9999999999999.9999999" '
        txtThaiWord.Text = ""
    End Sub

    Private Sub btnConvert_Click(sender As System.Object, e As System.EventArgs) Handles btnConvert.Click
        If Trim(txtNumber.Text) = "" Or Len(Trim(txtNumber.Text)) = 0 Then Exit Sub
        txtThaiWord.Text = NumberToThaiWord(txtNumber.Text)
    End Sub

    Function NumberToThaiWord(strNumber As String) As String
        Dim strThaiBaht As String = ""
        Dim strThaiStang As String = ""
        '// แยกเงินบาทกับสตางค์ออกจากกันด้วยเครื่องหมายทศนิยม
        Dim strBaht As String = "", strStang As String = ""
        ' ไว้นับรอบตามจำนวนหลัก
        Dim i As Byte
        '// คำประจำหลัก
        Dim arrUnit(6) As String
        '// เขียนแบบกระจายให้เห็นกันชัดๆ
        arrUnit(0) = "" ' แม้ว่าค่าที่เก็บไม่มีผล แต่จะช่วยจัดเรียงลำดับของ Array ทำให้ง่ายต่อการเขียนโค้ด
        arrUnit(1) = "สิบ"
        arrUnit(2) = "ร้อย"
        arrUnit(3) = "พัน"
        arrUnit(4) = "หมื่น"
        arrUnit(5) = "แสน"
        arrUnit(6) = "ล้าน"
        Dim arrNum As Object
        '// เช็คว่ามีจุดทศนิยมด้วยหรือไม่
        If InStr(strNumber, ".") <> 0 Then
            arrNum = Split(strNumber, ".")
            '// บาท
            strBaht = arrNum(0)
            '// สตางค์
            strStang = arrNum(1)
        Else
            strBaht = strNumber
            strStang = 0
        End If

        '// หาหลักล้าน ด้วยการนับหลักที่มากกว่า 7 หลัก
        Dim Million As Byte
        If (Len(strBaht) >= 7) Then
            Million = Len(strBaht) - 6
            '/ หาหลักที่เกินล้าน
            For i = 1 To Million
                If Mid$(strBaht, i, 1) <> 0 Then strThaiBaht = strThaiBaht + ThaiDigit(Mid$(strBaht, i, 1)) + arrUnit(Million - i)
            Next
            strThaiBaht = strThaiBaht + "ล้าน"
        End If

        '// หาเงินส่วนที่ไม่เกินล้าน ก็คือตัวเลข 6 หลัก (นับจากขวามาซ้ายโลด)
        strBaht = Trim(Microsoft.VisualBasic.Right(strBaht, 6))

        '// ก็คิดแบบจำนวนเกินล้านอีกรอบนั่นเอง
        For i = 1 To Len(strBaht)
            '// ดักค่าก่อนว่าหลักนั้นๆต้องมีค่าไม่ใช่ 0 เพื่อไม่ให้มีคำประจำหลักติดมา เช่น ...
            '// 301 จะต้องข้ามหลักสิบไป
            If Mid$(strBaht, i, 1) <> 0 Then
                '// วิธีการคิด ...
                '// ThaiDigit(Mid$(strBaht, i, 1)) คือ การรับค่าตัวเลขทีละหลักจากซ้ายไปขวา แล้วส่งไปเทียบค่าภาษาไทย
                '// เช่น 321
                '// รอบที่ 1 เมื่อ i = 1 ก็เลือกเอาเฉพาะหลักซ้ายมือสุด Mid("321", 1, 1) = 1 ตรงกับ "สาม"
                '// รอบที่ 2 เมื่อ i = 2 ก็เลือกเอาเฉพาะหลักที่สอง Mid("321", 2, 1) = 2 ตรงกับ "สอง"
                '// รอบที่ 3 เมื่อ i = 3 ก็เลือกเอาเฉพาะหลักที่สาม Mid("321", 3, 1) = 1 ตรงกับ "หนึ่ง"

                '// arrUnit(Len(strBaht) - i) คือ คำประจำหลัก
                '// เช่น 321 มีความยาว หรือ Len(strBaht) = 3
                '// รอบที่ 1 เมื่อ i = 1 ก็เอา Len(strBaht)= 3 ลบออกจากค่า i = 1 ตรงกับ arrUnit(2) = "ร้อย"
                '// รอบที่ 2 เมื่อ i = 2 ก็เอา Len(strBaht)= 3 ลบออกจากค่า i = 2 ตรงกับ arrUnit(1) = "สิบ"
                '// รอบที่ 3 เมื่อ i = 3 ก็เอา Len(strBaht)= 3 ลบออกจากค่า i = 3 ตรงกับ arrUnit(0) = "" (หลักหน่วยปล่อยว่าง)
                strThaiBaht = strThaiBaht & ThaiDigit(Mid$(strBaht, i, 1)) & arrUnit(Len(strBaht) - i)
                '// strThaiBaht = "สามร้อยสองสิบหนึ่ง"
            End If
        Next

        '// คำสุดท้ายคือคำลงท้ายด้วย "หนึ่ง" สำหรับการอ่านตัวเลขมากกว่า 2 หลักขึ้นไป ต้องเปลี่ยนเป็น "เอ็ด"
        '// เช่น 1001, 5001, 65001
        If Len(strBaht) > 1 And Microsoft.VisualBasic.Right$(strThaiBaht, 5) = "หนึ่ง" Then
            '// ตัดคำว่า "หนึ่ง" (มีความยาว 5 อักขระ) แล้วต่อท้ายด้วยคำว่า "เอ็ด"
            strThaiBaht = Mid$(strThaiBaht, 1, Len(strThaiBaht) - 5) & "เอ็ด"
        End If

        ' / ------------------------------------------------------------------------------------------------------
        '// หาค่าสตางค์ แต่ต้องเช็คก่อนว่ามีหน่วยสตางค์ด้วยหรือไม่
        ' / ------------------------------------------------------------------------------------------------------
        If strStang <> 0 Then
            '// หาความยาวของสตางค์
            '// กรณีสตางค์มีหลักเดียว ก็ใส่สิบตามหลังทันที
            If Len(strStang) = 1 Then
                strThaiStang = strThaiStang + ThaiDigit(Mid$(strStang, 1, 1)) + "สิบ"
            Else
                For i = 1 To Len(strStang)
                    If Mid$(strStang, i, 1) <> 0 Then
                        strThaiStang = strThaiStang + ThaiDigit(Mid(strStang, i, 1)) + arrUnit(Len(strStang) - i)
                    End If
                Next
            End If
        End If

        '// รวมบาทและสตางค์เข้าด้วยกัน
        If strStang <> 0 Then
            strThaiBaht = strThaiBaht + "บาท" + strThaiStang + "สตางค์"
        Else
            '// ไม่มีเศษสตางค์
            strThaiBaht = strThaiBaht + "บาทถ้วน"
        End If

        '// ต้องเปลี่ยนคำบางคำเพื่อให้ตรงกับภาษาไทยก่อน
        '// เมื่อค่าอินพุท คือ 321 ทำให้ได้ ...
        '// strThaiBaht = "สามร้อยสองสิบหนึ่ง"
        '// "สองสิบ" จะเป็น "ยี่สิบ" ทำให้ได้คำใหม่ คือ "สามร้อยยี่สิบหนึ่ง"
        '// "สิบหนึ่ง" จะเป็น "สิบเอ็ด" ทำให้ได้คำใหม่ คือ "สามร้อยยี่สิบเอ็ด"
        '// หรือจะคิดที่คำว่า "สิบหนึ่ง" ก่อนก็จะได้คำตอบเหมือนเดิม
        strThaiBaht = Replace(strThaiBaht, "หนึ่งสิบ", "สิบ")
        strThaiBaht = Replace(strThaiBaht, "สิบหนึ่ง", "สิบเอ็ด")
        strThaiBaht = Replace(strThaiBaht, "สองสิบ", "ยี่สิบ")
        strThaiBaht = Replace(strThaiBaht, "ร้อยหนึ่ง", "ร้อยเอ็ด")
        '// คำตอบสุดท้าย คือ "สามร้อยยี่สิบเอ็ด"
        '// คืนค่ากลับไป
        NumberToThaiWord = strThaiBaht
    End Function

    '// ฟังค์ชั่นรับค่าตัวเลขแต่ละหลักเข้ามา และคืนค่ากลับเป็นภาษาไทย
    Function ThaiDigit(Num As Byte) As String
        Select Case Num
            Case 0 : ThaiDigit = "ศูนย์"
            Case 1 : ThaiDigit = "หนึ่ง"
            Case 2 : ThaiDigit = "สอง"
            Case 3 : ThaiDigit = "สาม"
            Case 4 : ThaiDigit = "สี่"
            Case 5 : ThaiDigit = "ห้า"
            Case 6 : ThaiDigit = "หก"
            Case 7 : ThaiDigit = "เจ็ด"
            Case 8 : ThaiDigit = "แปด"
            Case 9 : ThaiDigit = "เก้า"
            Case Else : ThaiDigit = ""
        End Select
    End Function

    Private Sub txtNumber_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles txtNumber.KeyPress
        Select Case e.KeyChar
            Case "0" To "9"
                '// 0 - 9
                e.Handled = False
            Case Chr(8)
                '// Back Space
                e.Handled = False
            Case Chr(13)
                '// Enter
                e.Handled = False
            Case Chr(46) ' รหัส Ascii Code  ของเครื่องหมายจุดครับพี่น้อง
                '// ใช้ฟังค์ชั่น InStr (In String) เพื่อค้นหาเครื่องหมายจุดใน TextBox
                '// หากไม่เจอก็ให้กด . ได้ หากมีอยู่แล้วก็จะกดไม่ได้อีก (หลักการมีเท่านี้)
                If InStr(txtNumber.Text, ".") Then e.Handled = True
            Case Else
                '// ตัวอักขระอื่นๆ เช่น A a _ $ เราไม่รับเข้ามา ... จบ
                e.Handled = True
        End Select
    End Sub

    Private Sub btnExit_Click(sender As System.Object, e As System.EventArgs) Handles btnExit.Click
        Me.Dispose()
        Application.Exit()
    End Sub

End Class


Conclusion: สังเกตให้ดีๆว่าการแก้ปัญหาโจทย์เรื่องนี้ ล้วนแล้วมาจากคำสั่งระดับพื้นฐานทั้งน้านนนนครับพี่น้อง

ดาวน์โหลดโค้ดต้นฉบับ VB.Net (2010) ได้ที่นี่ ...

บันทึกการเข้า
สิ่งที่ดีกว่าการให้ คือการให้แบบไม่มีที่สิ้นสุด

ออฟไลน์ Mr.Den

  • Jr. Member
  • **
  • กระทู้: 73
  • เพศ: ชาย
Thank you มากคร๊าบ บ..

บันทึกการเข้า

ออฟไลน์ naien

  • Newbie
  • *
  • กระทู้: 36

บันทึกการเข้า