ดาวน์โหลดโปรแกรม RSS Reader ได้ที่นี่ ...

|
|
|
Visitors - Session views |       
7 ธันวาคม พ.ศ.2549 55 Users On-Line. |
|
Visitors - Page views |        1 กุมภาพันธ์ พ.ศ.2551 |
|
|
|
 |
|
แจกฟรีโค้ด VB6 กับการคำนวณหาหลักที่ 15 หรือ Check Digit ของ IMEI |
Category »
VB 6/VB.Net โดย : Webmaster เมื่อ 29/12/2554 เวลา: 15:09 | (อ่าน : 23766) |
ผมไม่ได้มากล่าวถึงกรณีคดีอีมี่ (IMEI) แต่ประการใดน่ะครับ แต่จะมาสาธยายในเรื่องวิชาการด้านการโปรแกรมมิ่ง ถึงวิธีการหาค่าหลักที่ 15 ของอีมี่ ซึ่งเป็นหลักตรวจสอบความถูกต้องของ 14 หลักแรก (กลุ่ม Mobile Phone) ... การมีหลักตรวจสอบ หรือ Check Digit มันไม่ได้นำมาใช้เฉพาะเรื่องของโทรศัพท์เท่านั้น ยังใช้กับรหัสบาร์โค้ดสินค้า บาร์โค้ดตามใบแจ้งหนี้เอย หรือบัตรประชาชนซึ่งจะมีหลักที่ 13 เป็นหลักตรวจสอบ (อ่านรายละเอียดได้ ... ที่นี่) ฯลฯ ... ถามว่าทำไมถึงต้องมี Check Digit ก็เพราะเพื่อตรวจสอบความถูกต้อง หรือป้องกันความผิดพลาดจากการป้อนข้อมูลนั่นเอง ซึ่งวิธีการหา Check Digit ของแต่ละที่ แต่ละงานมันก็จะแตกต่างกันออกไป ... สำหรับโจทย์(ง่ายๆ)ข้อนี้เรียกได้ว่ามันมีความน่าสนใจอยู่ไม่น้อยเลยทีเดียว มันเห็นภาพของการคิดวิเคราะห์โจทย์ออกมาได้ด้วยมือ แต่การจะเขียนเป็นโปรแกรมขึ้นมานั้นกลับไม่ได้ง่ายสำหรับหลายๆคนเลยครับ ... พี่น้อง |
 |
การคิดวิเคราะห์โจทย์

วิธีการหาหลักที่ 15 ของ IMEI จาก 14 หลักแรก (โดยแยกคิดเป็นหลักคี่ และ หลักคู่)
- กรณีที่เป็นหลักคี่ (หลักที่ 1, 3, 5, 7, 9, 11, 13) ให้นำค่าในแต่ละหลักของหลักคี่มาบวกกันไปเลย
ตัวอย่าง
- หลักที่ 1 คือ 3
- หลักที่ 3 คือ 8
- หลักที่ 5 คือ 3
- หลักที่ 7 คือ 0
- หลักที่ 9 คือ 8
- หลักที่ 11 คือ 3
- หลักที่ 13 คือ 9
ผลรวมของหลักคี่คือ 34
- กรณีที่เป็นหลักคู่ (หลักที่ 2, 4, 6, 8, 10, 12, 14) จะต้องนำค่าในแต่ละหลักมาคูณด้วย 2 ก่อน โดยมีเงื่อนไขเพิ่มดังนี้
- หากค่าในหลักคู่มาคูณด้วย 2 แล้วได้คำตอบเป็นเลขหลักเดียว ก็นำไปบวกกับหลักคู่อื่นๆได้เลย
- หากค่าในหลักคู่มาคูณด้วย 2 แล้วได้คำตอบเป็นเลข 2 หลัก จะต้องแยกเลข 2 หลักนี้ออกมาบวกกันก่อน แล้วค่อยนำไปบวกกับหลักคู่อื่นๆ
ตัวอย่าง
- หลักที่ 2 คือ 5 --> 5 x 2 = 10 --> (1 + 0) = 1
- หลักที่ 4 คือ 4 --> 4 x 2 = 8
- หลักที่ 6 คือ 9 --> 9 x 2 = 18 --> (1 + 8) = 9
- หลักที่ 8 คือ 4 --> 4 x 2 = 8
- หลักที่ 10 คือ 6 --> 6 x 2 = 12 --> (1 + 2) = 3
- หลักที่ 12 คือ 2 --> 2 x 2 = 4
- หลักที่ 14 คือ 7 --> 7 x 2 = 14 --> (1 + 4) = 5
ผลรวมของหลักคี่คือ 38
- ให้นำผลรวมของหลักคี่ และ ผลรวมหลักคู่ มาบวกกัน นั่นคือ 34 + 38 = 72
- ขั้นตอนสุดท้าย คือ การหาหลักที่ 15
จะมีวิธีการคิดดังนี้
- หากผลรวมของหลักคี่+หลักคู่ลงท้ายด้วยค่า 0 เช่น 70 ก็ให้ถือว่าค่า 0 นี้เป็นคำตอบ (Check Digit หลักที่ 15)
- หากไม่ใช่ ต้องเลื่อนไปหาค่าที่ลงท้ายด้วย 0 ถัดไป โดยค่าที่อยู่ห่างออกไปจากผลรวมหลักคี่+หลักคู่นั้นจะเป็นคำตอบ เช่น
ผลลัพธ์ได้ 55 ค่าที่จะลงท้ายด้วย 0 ถัดไปคือ 60 ดังนั้นเอา 60 - 55 จะได้คำตอบคือ 5 ผลลัพธ์ได้ 67 ค่าที่จะลงท้ายด้วย 0 ถัดไปคือ 70 ดังนั้นเอา 70 - 67 จะได้คำตอบคือ 3 ในตัวอย่างนี้ คือ 80 - 72 จะได้คำตอบคือ 8
|
คำว่าเลขในที่นี้ คือ เลขจำนวนเต็มบวกน่ะครับ ก่อนที่จะอธิบายเรื่องการคิดที่จะเขียนโปรแกรม ผมขอกล่าวพาดพิงไปยังสมัยประถมซ่ะก่อนน่ะครับท่านประธานที่เคารพ เราทุกคนคงเคยเรียนเรื่องการหารกันมาแล้ว เวลาที่เราหารเลขจำนวนเต็มใดๆมันก็จะมีทั้งคำตอบและเศษ (หารลงตัวเศษก็เป็น 0 ล่ะครับพี่น้อง) เช่น 25 / 2 ได้คำตอบ 12 เศษ 1 หรือ 33 / 3 ได้คำตอบ 11 เศษ 0 ... ในด้านโปรแกรมมิ่งสำหรับภาษาระดับสูง มันก็จะมาหารแบบนี้ไม่ได้ แต่มันสามารถหารแยกส่วนออกจากกันได้ โดยใช้โอเปอร์เรเตอร์ 2 ตัว คือ (เครื่องหมายสำหรับ Visual Basic น่ะครับ ... พี่น้อง)
\ (ดิฟ) คือ การหารแบบตัดเศษ เช่น 25 \ 2 ได้คำตอบคือ 12 เท่านั้น เพราะตัดเศษออกไป
Mod (ม็อด) คือ การหารแบบเอาเศษ เช่น 25 Mod 2 ได้คำตอบคือ 1 ผมจะกล่าวถึงความน่าอัศจรรย์ใจของ Mod นั่นคือ ค่าจำนวนเต็มใดๆที่นำไป Mod (เป็นตัวหารเอาเศษ) นั้น จะได้ค่าต่ำสุดคือ 0 และ ค่าสูงสุด คือ ค่าที่นำไป Mod - 1 เสมอ เช่น
Mod 2 คำตอบจะได้ 0, 1
Mod 8 คำตอบจะได้ 0, 1, 2, 3, 4, 5, 6, 7
Mod 10 คำตอบจะได้ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
มาดูการแก้ปัญหาในแต่ละข้อ
- เราจะรู้ได้อย่างไรว่า หลักต่างๆตามโจทย์ที่ตั้งไว้อันไหนมันเป็นหลักคู่ หรือ หลักคี่ (บางคนอาจจะนึกถึงการวนลูป 2 ครั้ง แยกเอาหลักคู่ หลักคี่แทน) ... ขอพาดพิงไปสมัยประถมอีกแล้วครับท่านประธาน 55555+ เลขจำนวนเต็มใดๆที่หารด้วย 2 ลงตัว (เศษเป็น 0) มันก็คือเลขคู่ หากมันมีเศษก็คือเลขคี่ แล้วเศษที่ว่านี่มันมีแต่ 1 เท่านั้น จริงมั้ยครับท่านประธาน ... เอ้า โป๊ะเช๊ะเข้าทางโจรป่าละเมาะล่ะครับ นั่นคือการนำหลักแต่ละหลักมา Mod 2 ยังไงล่ะครับ ... พี่น้อง 55555+
- สำหรับหลักคู่ เราจะใช้เงื่อนไขอะไรทดสอบว่าค่าที่คูณด้วย 2 นั้น มันมี 1 หรือ 2 หลัก
ทางแก้ปัญหา ...
- ใช้การวัดความยาวหรือจำนวนหลักของค่าที่ได้ นั่นคือ IF Len(ค่า) > 1
- หากหลักคู่นั้น (แต่มีเลขโดดๆตัวเดียว) มีค่าตั้งแต่ 5 ขึ้นไป (5, 6, 7, 8, 9) เมื่อคูณด้วย 2 แล้วจะทำให้ได้ผลลัพธ์มีจำนวน 2 หลัก นั่นคือ IF ค่า >= 5
- ใช้การจัดรูปแบบให้ได้ตัวเลขขนาด 2 หลัก
- ผลรวมหลักคู่+ผลรวมหลักคี่ ... ง่ายมากไม่ขอกล่าวถึงครับ
- การหาคำตอบในหลักที่ 15 ก็ไม่ได้ยากเลย ...
- หากค่าทางขวามือสุดของผลรวมหลักคู่+ผลรวมหลักคี่ มีค่าเป็น 0 ก็ตอบ 0 เลย
- หากไม่ใช่ ให้เอาค่าทางขวามือสุดของผลรวมหลักคู่+ผลรวมหลักคี่ ลบออกด้วย 10 ก็คือคำตอบ
|
 Design Time
 Run Time
มาดูโค้ดกันเถอะ ...
Option Explicit
Private Sub Form_Load()
' ตั้งฟอร์มอยู่กึ่งกลางจอภาพ
Me.Move (Screen.Width - Width) \ 2, (Screen.Height - Height) \ 2
' เคลียร์หน้าจอ
Call SetupScreen
' ตัวอย่าง
txtFourteenDigit.Text = "35843904863297" ' <-- คำตอบ = 8
'txtFourteenDigit.Text = "35780502398494" ' <-- คำตอบ = 2
'txtFourteenDigit.Text = "358639048632965" ' <-- คำตอบ = 5
'txtFourteenDigit.Text = "35688202005060" ' <-- คำตอบ = 6
End Sub
' / -------------------------------------------------------------------------------------------------------------
' / โปรแกรมย่อยในการเคลียร์หน้าจอการแสดงผล
Sub SetupScreen()
' / -------------------------------------------------------------------------------------------------------------
txtFourteenDigit.Text = ""
txtCheckDigit.Text = ""
txtIMEI.Text = ""
End Sub
' / -------------------------------------------------------------------------------------------------------------
' คลิ๊กปุ่มเพื่อทำการคำนวณหา Check Digit หลักที่ 15 ของ IMEI 14 หลักแรก
Private Sub cmdCal_Click()
' / -------------------------------------------------------------------------------------------------------------
Dim i As Integer
' จำนวน 14 หลัก
Dim Digit As Byte
' ผลรวมหลักคี่
Dim SumOdd As Integer
' ผลรวมหลักคู่
Dim SumEven As Integer
' ผลรวมหลักคี่บวกหลักคู่
Dim Sum14Digit As Integer
' ผลรวมชั่วคราวของการคูณ 2 ในหลักคู่
Dim EvenTemp As Integer
' ตรวจสอบตัวเลขจำนวน 14 หลักแรกว่าป้อนมาครบหรือไม่
If Trim(txtFourteenDigit.Text) = "" Or Len(Trim$(txtFourteenDigit.Text)) < 14 Then
MsgBox "กรุณาป้อนตัวเลข 14 หลักแรกของ IMEI ให้ครบก่อนด้วย.", _
vbOKOnly + vbExclamation, "รายงานความผิดพลาด"
Exit Sub
End If
' วนรอบ 14 ครั้งจาก 14 หลักแรกของ IMEI
For Digit = 1 To Len(txtFourteenDigit.Text)
' หากหารเอาเศษได้ผลลัพธ์เป็น 0 แสดงว่าหลักคู่ เราจะมาพิจารณาหลักนี้โดยให้คูณด้วย 2 เข้าไป
If (Digit Mod 2) = 0 Then
' Mid$(Val(txtFourteenDigit.Text), Digit, 1) * 2 คือใช้หลักคู่มาคูณด้วย 2
' ผลลัพธ์นำมาจัดเรียงให้ได้ตัวเลข 2 หลัก
' Right$("00" & Mid$(Val(txtFourteenDigit.Text), Digit, 1) * 2, 2)
' เช่น หากได้ 8 ... ให้นำ "00" ต่อด้วย "8" ผลลัพธ์จะได้ "008"
' แต่ให้นับจากขวามา 2 หลัก ก็จะได้ผลลัพธ์เป็น "08"
EvenTemp = Right$("00" & Mid$(Val(txtFourteenDigit.Text), Digit, 1) * 2, 2)
' นำค่า 2 หลักที่ได้จากนิพจน์ทางด้านบนมาบวกกัน และต้องบวกเข้ากับผลรวมหลักคู่เดิมที่มีอยู่ด้วย เช่น
' กรณีหลัก 2 ก็บวกกับ 0 (ค่าใน SumEven)
' กรณีหลัก 4 ก็จะใช้การวนรอบในแต่ละหลัก แล้วมาบวกเข้าไปกับค่าเดิม (SumEven) 2 ครั้ง เช่น
' (สมมุติ) SumEven เดิมมีค่าเท่ากับ 1 ส่วนผลจากการคูณ 2 ในหลักที่ 4 มีค่าเท่ากับ 08
' รอบแรก SumEven = 1 + 0 เท่ากับ 1
' รอบสอง SumEven = 1 + 8 เท่ากับ 9
' ง่ายมั้ยครับพี่น้อง ... 55555+
For i = 1 To 2
SumEven = SumEven + Val(Mid$(EvenTemp, i, 1))
Next
' ตัวอย่างอีกแนวคิดที่ใช้คำสั่งและเงื่อนไขเข้าช่วย
'EvenTemp = Val(Mid(txtFourteenDigit.Text, Digit, 1)) * 2
' การใช้วิธีการนับความยาวของผลคูณหลักคู่ (เลือก IF ตัวใดตัวนึงน่ะครับ)
'If Len(EvenTemp) > 1 Then
' หรือ การเอาค่าที่ >= 5 มาเป็นเงื่อนไข
'If Mid$(txtFourteenDigit, Digit, 1) >= 5 Then
' For i = 1 To 2
' SumEven = SumEven + Val(Mid$(CStr(EvenTemp), i, 1))
' Next
'Else
' SumEven = SumEven + EvenTemp
'End If
' หากหารเอาเศษผลลัพธ์ได้ 1 แสดงว่าเป็นหลักคี่
Else
' การบวกของหลักคี่แต่ละหลัก อันนี้ง่ายหน่อยล่ะ จึงไม่ขออธิบายน่ะครับพี่น้อง
SumOdd = SumOdd + Mid$(Val(txtFourteenDigit.Text), Digit, 1)
End If
' สามารถรวมผลของหลักคู่ และหลักคี่ตรงนี้เลยก็ได้ แต่ผมแยกออกไปจาก Loop For น่ะครับ
' เพื่อให้มองเห็นง่ายๆ
Next
' ผลรวมหลักคู่และหลักคี่
Sum14Digit = SumOdd + SumEven
' / -------------------------------------------------------------------------------------------------------------
' หาค่าหลักที่ 15 หรือ หลักตรวจสอบความถูกต้อง (Check Digit) นั่นเอง โดยมีหลักการดังนี้
' 1. หากผลรวมของหลักคี่และหลักคู่รวมกันลงท้ายด้วย 0 ถือว่า 0 เป็นคำตอบได้เลยทันที
' 2. หากไม่ใช่ ต้องเลื่อนไปหาค่าที่ลงท้ายด้วย 0 ถัดไป และหาค่าที่อยู่ห่างกันนั้นเป็นคำตอบ เช่น
' ผลลัพธ์ได้ 55 ค่าที่จะลงท้ายด้วย 0 ถัดไปคือ 60 ดังนั้นเอา 60 - 55 จะได้คำตอบคือ 5
' ผลลัพธ์ได้ 67 ค่าที่จะลงท้ายด้วย 0 ถัดไปคือ 70 ดังนั้นเอา 70 - 67 จะได้คำตอบคือ 3
' ด้านบนคือการคิดและหาค่าด้วยมือ ปัญหาก็คือจะเขียนโปรแกรมออกมาได้ยังไง ...
' จากค่าตัวอย่าง 55 หรือ 67 เราจะเห็นได้เลยว่า จะต้องนำหลักขวามือสุดคือ 5 และ 7 ออกมา
' ง่ายๆเลยอาจจะใช้คำสั่ง Right ขวาสุดมา 1 ตัวก็ได้ แล้วลบออกด้วย 10 ก็คือคำตอบ
' แต่ที่ผมคิดคือการใช้โอเปอร์เรเตอร์ Mod (อีกแล้ว)
' ก็ Mod ด้วย 10 ยังไงล่ะครับ เพราะการ Mod ด้วย 10 จะทำให้มีค่าระหว่าง 0 - 9
' เช่น 55 Mod 10 ก็เหลือเศษ 5 และ 67 Mod 10 เหลือเศษ 7
' แล้วนำค่านี้ไปลบออกจาก 10 ก็จะเป็นคำตอบ เช่น 10 - 5 = 5 และ 10 - 7 = 3
' ไม่ว่าจะคิดแบบไหน ก่อนลงมือเขียนโปรแกรม จำเป็นจะต้องมีค่าสมมุติเพื่อทำการทำสอบก่อนเสมอ
' / -------------------------------------------------------------------------------------------------------------
' เมื่อออกแบบได้ตามนี้ ดังนั้นจึงไม่มีความจำเป็นต้องเขียนโค้ดให้มีเงื่อนไขใดๆมาเลย
' แค่มีฟังค์ชั่น (หรือคำสั่ง) Right มาดักเอาค่าหลักขวามือสุด หากกรณีผลรวมหลักคี่หลักคู่ลงท้ายด้วย 0
' จากตัวอย่าง 14 หลักแรก = 35843904863297
' ผลรวมของ Sum14Digit = 72 ... นั่นคือ 72 Mod 10 = 2
' 10 - 2 = 8 <-- คือคำตอบของหลักที่ 15
txtCheckDigit.Text = Right$(10 - Sum14Digit Mod 10, 1)
' ไม่จำเป็นต้องใส่วงเล็บ เพราะ Mod มีลำดับความสำคัญสูงกว่าการลบ จึงต้องทำการ Mod ก่อน
' หรือกระจายบรรทัดคำสั่งและเงื่อนไขออกมาให้มองเห็นง่ายๆ
'If Sum14Digit Mod 10 = 0 Then
' txtCheckDigit.Text = 0
' หาก Mod แล้วไม่ใช่ 0 ให้เลื่อนไปหาค่าที่มีศูนย์ต่อท้ายถัดไป แล้วลบออกด้วย 10
'Else
' txtCheckDigit.Text = (10 - Sum14Digit Mod 10)
'End If
' / -------------------------------------------------------------------------------------------------------------
' เอาค่าที่ได้มาจัดเรียงเป็นคำตอบสุดท้าย
txtIMEI.Text = txtFourteenDigit.Text & txtCheckDigit.Text
' / -------------------------------------------------------------------------------------------------------------
End Sub
' / -------------------------------------------------------------------------------------------------------------
' / ตรวจสอบการกดคีย์ใน TextBox ได้เฉพาะตัวเลข 0 - 9
' / Index ก็คือค่า ASCII Code ของ Character แต่ละตัว
Function CheckDigitOnly(Index As Integer) As Integer
' / -------------------------------------------------------------------------------------------------------------
Select Case Index
' 0 - 9
Case 48 To 57
' Back Space
Case 8
' Enter
Case 13
' ไม่ต้องการให้สามารถกดคีย์อื่นๆได้ ก็คืนค่ากลับเป็น 0 เสมือนไม่มีการกดคีย์ใดๆเลย
Case Else
Index = 0
End Select
CheckDigitOnly = Index
End Function
Private Sub txtFourteenDigit_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyReturn Then
KeyAscii = 0
Call cmdCal_Click
Else
KeyAscii = CheckDigitOnly(KeyAscii)
End If
End Sub
|
Conclusion: โจทย์ข้อนี้จะเห็นได้อย่างชัดเจนเลยว่า อาศัยความรู้แค่ระดับพื้นฐานชั้นประถมมาช่วยในการแก้ปัญหาเท่านั้นเองครับ ใช้การคิดวิเคราะห์โจทย์ (หาคำตอบด้วยการคำนวณด้วยมือ) แล้วผสมผสานกับการใช้คำสั่งพื้นๆของตัวแปลภาษาแต่ละตัว ... ลาทีเมียเก่า เอ้ย ปีเก่า ขอส่งความสุขสวัสดีปีใหม่แด่เพื่อนพ้องน้องพี่โปรแกรมเมอร์ทุกๆท่านครับ
|
|