在EXCEL中VBA编程检验身份证号码有效性

Bertha 。 2024-03-31 13:18 236阅读 0赞

*2022-12-05 改正代码中错别字,规范表述

*2022-11-30 1.增加了过程clearB()用来清除B1:Bx原有的出错说明,在过程examIdentityCard() 开头调用

2.修改了过程examIdentityCard(),如果身份证号码包含多余的字符则提示”包括多余字符;”

参加数据治理工作,使用库表转换功能把excel表格数据上传到平台上的数据库,在进行数据质量检测时,有许多身份证号码数据被检测为“非身份证号码”,但没有更具体的说明,比如是数据位数不对(应为15位或18位),出生日期不对(1986-02-30),或者是末位校验码不对……等等。

把这些包含被检测为“非身份证号码”的异常数据导出为Excel表格,再用VBA写代码来校验分析。

网上的关于检验身份证号码的代码很多,但基本不能拿来就用,还得结合自己的实际应用情况进行修改完善。

编写过程中的体会主要有两点:

一是对于18位身份证号码,末位的x可能被写成乘号×、全角大写x、全角小写x,而我们用的数据库系统数据质量检测只认大写半角X,写成乘号×、全角大写x、小写半角x都会被认为“非身份证号码”。这些都要进行预处理,将它们转换为大写半角X。预处理代码如下:

  1. v = Rng.text
  2. '检查是否包含×
  3. If InStr(v, "×") > 0 Then
  4. v = Replace(v, "×", "X", 1, -1)
  5. Range("B" & Rng.Row).Value = Range("B" & Rng.Row).Value & "×应为X;"
  6. End If
  7. '检查是否包含全角大写x
  8. If InStr(v, "X") > 0 Then
  9. v = Replace(v, "X", "X", 1, -1)
  10. Range("B" & Rng.Row).Value = Range("B" & Rng.Row).Value & "×应为X;"
  11. End If
  12. '检查是否包含全角小写x
  13. If InStr(v, "x") > 0 Then
  14. v = Replace(v, "x", "X", 1, -1)
  15. Range("B" & Rng.Row).Value = Range("B" & Rng.Row).Value & "×应为X;"
  16. End If

二是身份证号码可能包含非打印字符,不做处理的话,就会影响Len()返回值,进而影响到身份证位数的判断。而在实际处理中,发现VBA提供的Trim()、Application.WorksheetFunction.Clean()都清理不干净,网上的代码也不适合我的情况,于是自己DIY了一个:

  1. Function DelUnprintChar(s) As String
  2. r = ""
  3. For iPosition = 1 To Len(s) Step 1
  4. c = Mid(s, iPosition, 1)
  5. If ((c >= "0") And (c <= "9")) Or ((c >= "a") And (c <= "z")) Or ((c >= "A") And (c <= "Z")) Then
  6. r = r & c
  7. End If
  8. Next
  9. DelUnprintChar = r
  10. End Function

完整的代码如下(身份证号码数据在A1:Ax,数据错误显示在B1:Bx)。:

  1. Function exam18(v) As String
  2. Dim cd1, r
  3. r = ""
  4. '下面检验出生日期是否正确
  5. cd1 = Mid(v, 7, 4) & "-" & Mid(v, 11, 2) & "-" & Mid(v, 13, 2)
  6. If Not IsDate(cd1) Then
  7. r = "出身日期" & cd1 & "无效;"
  8. Else
  9. r = examIdentityCardLastDigit(v)
  10. End If
  11. exam18 = r
  12. End Function
  13. Function exam15(v) As String
  14. '15位身份证号码进行校验
  15. Dim a, r
  16. r = ""
  17. '是否全数字
  18. If Not IsNumeric(r) Then
  19. r = "15位身份证号码应全是数字;"
  20. Else
  21. '下面检验出生日期是否正确
  22. a = Mid(v, 7, 2) & "-" & Mid(v, 9, 2) & "-" & Mid(v, 11, 2)
  23. If Not IsDate(a) Then
  24. r = "出生日期" + a + "无效;"
  25. End If
  26. End If
  27. exam15 = r
  28. End Function
  29. Function examIdentityCardLastDigit(v) As String
  30. Dim i, arr1(), arr2(), r, s
  31. arr1 = Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2) '系数
  32. arr2 = Array("1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2") '对应的结果
  33. r = ""
  34. t = Left(v, 17)
  35. If Not IsNumeric(t) Then
  36. r = "身份证号码前17位应是数字;"
  37. Else
  38. s = 0
  39. For i = 1 To 17
  40. t = Mid(v, i, 1) '取出每位数
  41. s = s + t * arr1(i - 1) '求和
  42. Next i
  43. s = s Mod 11 '取余数
  44. t = Mid(v, 18, 1)
  45. 'If t = "x" Then
  46. ' t = "X"
  47. 'End If
  48. If arr2(s) <> t Then '判断是否与最后一位相等
  49. r = "末位代码应为" & arr2(s) & ";"
  50. End If
  51. End If
  52. examIdentityCardLastDigit = r
  53. End Function
  54. Function DelUnprintChar(s) As String
  55. r = ""
  56. For iPosition = 1 To Len(s) Step 1
  57. c = Mid(s, iPosition, 1)
  58. If ((c >= "0") And (c <= "9")) Or ((c >= "a") And (c <= "z")) Or ((c >= "A") And (c <= "Z")) Then
  59. r = r & c
  60. End If
  61. Next
  62. DelUnprintChar = r
  63. End Function
  64. Sub clearB()
  65. '清除B1:Bx原有的出错说明
  66. Range("b1", Cells(Rows.Count, "b").End(xlUp)).Clear
  67. End Sub
  68. Sub examIdentityCard()
  69. Dim r, s, v
  70. For Each Rng In Range("a1", Cells(Rows.Count, "a").End(xlUp))
  71. v = Rng.text
  72. '检查是否包含×
  73. If InStr(v, "×") > 0 Then
  74. v = Replace(v, "×", "X", 1, -1)
  75. Range("B" & Rng.Row).Value = Range("B" & Rng.Row).Value & "×应为X;"
  76. End If
  77. '检查是否包含全角大写x
  78. If InStr(v, "X") > 0 Then
  79. v = Replace(v, "X", "X", 1, -1)
  80. Range("B" & Rng.Row).Value = Range("B" & Rng.Row).Value & "×应为X;"
  81. End If
  82. '检查是否包含全角小写x
  83. If InStr(v, "x") > 0 Then
  84. v = Replace(v, "x", "X", 1, -1)
  85. Range("B" & Rng.Row).Value = Range("B" & Rng.Row).Value & "×应为X;"
  86. End If
  87. r = Len(v)
  88. v = DelUnprintChar(v)
  89. If Len(v) < r Then
  90. Range("B" & Rng.Row).Value = Range("B" & Rng.Row).Value & "包括多余字符;"
  91. End If
  92. If Len(v) = 15 Then
  93. r = exam15(v)
  94. If Len(r) <> 0 Then
  95. Range("B" & Rng.Row).Value = Range("B" & Rng.Row).Value + r
  96. End If
  97. ElseIf Len(v) = 18 Then
  98. If InStr(v, "x") > 0 Then
  99. v = UCase(v) '小写变大写
  100. Range("B" & Rng.Row).Value = Range("B" & Rng.Row).Value & "x应为X;"
  101. End If
  102. r = exam18(v)
  103. If Len(r) <> 0 Then
  104. Range("B" & Rng.Row).Value = Range("B" & Rng.Row).Value + r
  105. End If
  106. Else
  107. Range("B" & Rng.Row).Value = "身份证号码位数应为15或18位;"
  108. End If
  109. Next
  110. End Sub

发表评论

表情:
评论列表 (有 0 条评论,236人围观)

还没有评论,来说两句吧...

相关阅读