thongkorn โพสต์ 2020-5-8 15:51:44

[VB.NET] การสุ่มหมายเลขบัตรประชาชน 13 หลัก และตรวจสอบความถูกต้องของรหัสหลักที่ 13

http://www.g2gnet.com/webboard/images/vbnet/genidcard.png

แอดมินแจกโค้ดนี้เอาไว้เมื่อราวๆปี 2549 เอาไว้สุ่มหมายเลขบัตรประชาชนเอาเพื่อไปเล่นเกมส์ 5555+ ... เรามาดูวิธีการคิดกันครับ ...


วิธีคิดในการสุ่มเลขจำนวน 12 หลัก แล้วหา Check Digit หลักที่ 13 ... เช่น 7736830472815 เมื่อ 5 คือหลักที่ 13 หรือ Check Digit ...
หาผลรวมตั้งแต่หลักที่ 1 ไปจนถึงหลักที่ 12 (นับจากซ้ายไปขวา)
โดยให้หลักที่ 1 คูณด้วยน้ำหนักประจำหลัก = 13 ... (7 x 13)
โดยให้หลักที่ 2 คูณด้วยน้ำหนักประจำหลัก = 12 ... (7 x 12)
โดยให้หลักที่ 3 คูณด้วยน้ำหนักประจำหลัก = 11 ... (3 x 11)
โดยให้หลักที่ (เพิ่มขึ้น 1) คูณด้วยน้ำหนักประจำหลัก = (ลดลง 1)
โดยให้หลักที่ 12 คูณด้วยน้ำหนักประจำหลัก = 2 ... (1 x 2)

จากนั้นนำผลการคูณของแต่ละหลักมารวมกันเข้าไป

หลักแต่ละหลัก คือ Val(Mid$(txtIDcard.Text, Count, 1))
น้ำหนักของแต่ละหลัก คือ (14 - Count) เมื่อ Count เริ่มต้นจาก 1 ไปสิ้นสุดที่ 12 ดังนั้นค่านี้ (14 - Count) จึงเริ่มต้นค่าจาก 13, 12, 11, ..., สิ้นสุดที่ 2 ครับผม
จะได้โค้ดดังนี้ ...
Sum = 0
For Count = 1 To 12
    Sum = Sum + Val(Mid$(txtIDcard.Text, Count, 1)) * (14 - Count)
Next
ลักษณะของการนำตัวแปร Sum มาเวียนใช้งาน สำหรับมือใหม่หัดขับในการพัฒนาโปรแกรม พยายามศึกษาการทำงานมันให้ดีน่ะครับ เพราะคุณต้องนำมันมาใช้งานตลอดทั้งชีวิตของการเขียนโปรแกรมของคุณแน่ๆ

นำผลรวมที่ได้มา Mod (การหารเอาเศษ) ด้วย 11 นั่นคือค่าที่เราจะได้ก็คือ 0, 1, 2, .. , 10 (Sum Mod 11)
เพิ่มเติม: เรา Mod ด้วยอะไร ก็จะได้ค่าสูงสุด (ที่เป็นไปได้) ของตัว Mod ลบด้วย 1 เสมอ (ในที่นี้คือ 11 - 1 = 10)
เพิ่มเติม: เรามักจะนำตัวเลขจำนวนเต็มมา Mod ด้วย 2 เพื่อตรวจสอบว่าเลขจำนวนเต็มนั้นมันเป็นเลขคู่ หรือ เลขคี่ หาก Mod แล้วได้ 0 นั่นคือ เป็นเลขคู่ หาก Mod แล้วผลลัพธ์เป็น 1 แสดงว่าเป็นเลขคี่

เอ้ามาว่ากันต่อไป ...
จากนั้นให้ลบออกด้วย 11 ก็จะทำให้ได้ค่าตั้งแต่ 1, 2, 3, ... , 11 (11 - (Sum Mod 11))
แล้วให้เลือกตัวขวามือสุดมาหนึ่งตัว ด้วยคำสั่ง Right$ --> Right$(Str(11 - (Sum Mod 11)), 1)
สุดท้ายก็ให้นำมาเปรียบเทียบกับหลักที่ 13 ของหมายเลขบัตรประชาชน ว่ามันตรงกันหรือไม่ ?
หากตรงกันก็แสดงว่า เป็นบัตรแท้, หากไม่ตรงกัน ก็คือ บัตรเก๊ เท่านี้เองครับพี่น้อง

มาดูโค้ดฉบับเต็มกันเถอะ ...
Public Class frmCheckIDCard

    Private Sub btnRandom_Click(sender As System.Object, e As System.EventArgs) Handles btnRandom.Click
      txtIDCard.Clear()
      '/ สุ่มหาตัวเลขมาทั้งหมด 12 หลัก โดยที่หลักแรกต้องไม่ใช่ 0 และ 9 ด้วย
      '/ เรียกไปยังฟังค์ชั่น RandomNumber โดยไม่มีการส่งค่าใดๆไป แต่จะต้องรับค่าที่ได้กลับมา
      txtIDCard.Text = RandomNumber()

      ' หลักคิดสำหรับ 12 หลักแรก
      ' เริ่มต้นคำนวณหาค่าผลรวมตัวเลขทั้ง 12 หลักแรก ดังนี้
      ' หาผลรวมตั้งแต่หลักที่ 1 ไปจนถึงหลักที่ 12 (นับจากซ้ายไปขวา)
      ' โดยให้หลักที่ 1 คูณด้วยน้ำหนักประจำหลัก = 13
      ' โดยให้หลักที่ 2 คูณด้วยน้ำหนักประจำหลัก = 12
      ' โดยให้หลักที่ 3 คูณด้วยน้ำหนักประจำหลัก = 11
      ' โดยให้หลักที่ .. คูณด้วยน้ำหนักประจำหลัก = ..
      ' โดยให้หลักที่ 12 คูณด้วยน้ำหนักประจำหลัก = 2
      ' จากนั้นนำผลการคูณของแต่ละหลักมารวมกันเข้าไป

      ' หลักแต่ละหลัก คือ Val(Mid$(txtIDcard.Text, Count, 1))
      ' น้ำหนักของแต่ละหลัก คือ (14 - Count) เมื่อ Count เริ่มต้นจาก 1 ไปสิ้นสุดที่ 12
      ' ดังนั้นค่านี้ (14 - Count) จึงเริ่มต้นค่าจาก 13, 12, 11, ..., สิ้นสุดที่ 2 ครับผม
      Dim Sum As Integer = 0
      For Count As Byte = 1 To 12
            Sum = Sum + Val(Mid$(txtIDCard.Text, Count, 1)) * (14 - Count)
      Next

      ' / --------------------------------------------------------------------
      ' ขั้นตอนนี้ คือ การหาค่า Check Digit (หลักที่ 13) หรือ หลักตรวจสอบความถูกต้อง
      ' นำผลรวมที่ได้ (Sum) มา Mod (การหารเอาเศษ) ด้วย 11 นั่นคือค่าที่เราจะได้ก็คือ 0, 1, 2, .. , 10 (Sum Mod 11)
      ' จากนั้นให้ลบออกด้วย 11 ก็จะทำให้ได้ค่าตั้งแต่ 1, 2, 3, ... , 11 (11 - (Sum Mod 11))
      ' แล้วให้เลือกตัวขวามือสุดมาหนึ่งตัว ด้วยคำสั่ง Right$ --> Right$(Str(11 - (Sum Mod 11)), 1)
      ' ค่าสุดท้ายนี้ก็คือ หลักที่ 13 หรือ หลักตรวจสอบความถูกต้อง (Check Digit) นั่นเอง
      '
      Dim CheckDigit As String = Microsoft.VisualBasic.Right(Str(11 - (Sum Mod 11)), 1)
      txtIDCard.Text = txtIDCard.Text + CheckDigit
    End Sub

    ' / --------------------------------------------------------------------
    ' ฟังค์ชั่นที่ใช้ในการสุ่มตัวเลขจำนวน 12 หลัก ไม่มีการรับค่า แต่จะต้องส่งค่าคืนกลับไป (Return)
    ' ดังนั้นเราต้องใช้เป็นแบบฟังค์ชั่น (Function)จะใช้ Sub Program ไม่ได้
    ' / --------------------------------------------------------------------
    Function RandomNumber() As String
      RandomNumber = String.Empty

      ' เริ่มต้นในการสุ่มตัวเลข
      Randomize()
      Dim rndID As New Random
      '/ เพื่อบ่งบอกว่าหลักแรกหาค่าได้สำเร็จแล้วหรือไม่
      Dim blnFlag As Boolean = False
      Dim i As Byte = 1
      ' สุ่มเลขจำนวน 12 หลัก โดยที่หลักแรกต้องไม่ใช่ 0 และ 9
      ' i เริ่มต้นจาก 1
      While i <> 12
            ' Not False หรือ ไม่จริง ก็คือ เท็จ (หรือเขียน blnFlag = False) ... แสดงว่าตอนนี้เรากำลังจะหาตัวเลขหลักแรกอยู่
            If Not blnFlag Then
                ' สุ่มตัวเลขหลักแรก ต้องไม่ให้มีค่าเป็น 0 และ 9 ... นี่คือการทำซ้ำ หรือ Repetitive
                Do
                  RandomNumber = rndID.Next(0, 9)

                  ' ทำจนกว่าหลักแรกต้องไม่เท่ากับ 0 และ 9 (เงื่อนไขต้องใช้ AND)
                  ' เช่น เมื่อ RandomNumber มีค่า = 1
                  ' ทำให้ได้เงื่อนไข 1 <> 0 และ 1 <> 9 (True AND True = True) ... เงื่อนไขเป็น "จริง" ให้ออกจาก Loop
                  ' หรือ เมื่อ RandomNumber มีค่า = 9
                  ' ทำให้ได้เงื่อนไข 9 <> 0 และ 9 <> 9 (True AND False = False) ... เงื่อนไขเป็น "เท็จ" ให้วน Loop ต่อไป
                Loop Until RandomNumber <> 0 And RandomNumber <> 9

                ' หรือ ใช้เงื่อนไข Until แต่กลับกันด้วย Not ...
                'Loop Until Not RandomNumber = 0 And Not RandomNumber = 9

                ' หรือใช้ While แต่เงื่อนไขต้องกลับกันกับแบบ Until และต้องใช้ OR แทนที่
                ' เช่น เมื่อ RandomNumber มีค่า = 1
                ' ทำให้ได้เงื่อนไข 1 = 0 หรือ 1 = 9 (False OR False = False) ... เงื่อนไขเป็น "เท็จ" ให้ออกจาก Loop
                ' หรือ เมื่อ RandomNumber มีค่า = 9
                ' ทำให้ได้เงื่อนไข 9 = 0 หรือ 9 = 9 (False OR True = True) ... เงื่อนไขเป็น "จริง" ให้วน Loop ต่อไป
                'Loop While RandomNumber = 0 Or RandomNumber = 9

                ' แจ้งว่าหลักแรกหาตัวเลขที่ไม่ใช่ 0 หรือ 9 เสร็จสมบูรณ์แล้ว หลักต่อไปจะได้ไม่ต้องเข้าไป Do Loop อีก
                blnFlag = True
            End If

            ' หาค่าจำนวนหลักที่เหลือ แล้วส่งค่าคืนกลับของฟังค์ชั่นไปได้เลย
            RandomNumber = RandomNumber & rndID.Next(0, 9)
            '// Increment Counter
            i += 1
      End While
    End Function

    ' / --------------------------------------------------------------------
    ' / ตรวจสอบหมายเลขบัตรประชาชน
    Private Sub btnCheck_Click(sender As System.Object, e As System.EventArgs) Handles btnCheck.Click
      '/ ไม่มีการป้อนข้อมูล ก็ให้ออกจากโปรแกรมย่อยไป
      If txtIDCard.Text = "" Or txtIDCard.Text.Trim.Length = 0 Then Exit Sub
      ' ความยาวต้องเท่ากับ 13 หลัก
      If Len(txtIDCard.Text) < 13 Then
            MsgBox("กรุณากรอกหมายเลขบัตรประชาชนให้ครบทั้ง 13 หลักด้วย.", vbOKOnly + vbExclamation, "รายงานความผิดพลาด")
            Exit Sub
      End If
      ' หาผลรวมตั้งแต่หลักที่ 1 ไปจนถึงหลักที่ 12
      Dim Sum As Integer = 0
      For Count As Byte = 1 To 12
            Sum = Sum + Val(Mid(txtIDCard.Text, Count, 1)) * (14 - Count)
      Next
      ' เปรียบเทียบค่าที่ได้กับหลักที่ 13
      If Microsoft.VisualBasic.Right(txtIDCard.Text, 1) = Microsoft.VisualBasic.Right(Str(11 - (Sum Mod 11)), 1) Then
            MessageBox.Show("หมายเลขบัตรประชาชน " & txtIDCard.Text & " ถูกต้อง.", "รายงานการตรวจสอบ", MessageBoxButtons.OK, MessageBoxIcon.Information)
      Else
            MessageBox.Show("หมายเลขบัตรประชาชน " & txtIDCard.Text & " ไม่ถูกต้อง.", "รายงานการตรวจสอบ", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
      End If
    End Sub

    Private Sub frmCheckIDCard_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
      txtIDCard.Focus()
    End Sub

    Private Sub txtIDCard_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles txtIDCard.KeyPress
      If Asc(e.KeyChar) = 13 Then
            e.Handled = True
            btnCheck_Click(sender, e)
      Else
            e.Handled = CheckDigitOnly(Asc(e.KeyChar))
      End If
    End Sub

    ' / ฟังค์ชั่นในการป้อนเฉพาะค่าตัวเลขได้เท่านั้น
    Function CheckDigitOnly(ByVal index As Integer) As Boolean
      Select Case index
            Case 48 To 57 ' เลข 0 - 9
                CheckDigitOnly = False
            Case 8, 13 ' Backspace = 8, Enter = 13
                CheckDigitOnly = False
            Case Else
                CheckDigitOnly = True
      End Select
    End Function

End Class

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

g2gsoftuser โพสต์ 2022-10-25 14:26:03

ขอบคุณครับ
หน้า: [1]
ดูในรูปแบบกติ: [VB.NET] การสุ่มหมายเลขบัตรประชาชน 13 หลัก และตรวจสอบความถูกต้องของรหัสหลักที่ 13