找回密码
 欢迎注册
查看: 26593|回复: 28

[求助] 谁能用mathematica写个校验身份证的子函数?

[复制链接]
发表于 2019-4-19 13:26:29 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?欢迎注册

×
  1. (*身份证检验码*)
  2. Clear["Global`*"];(*Clear all variables*)
  3. (*没考虑身份证号码最后一位x的情况*)
  4. fun[id_]:=Module[{ids,dot},
  5.     jym={7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
  6.     ids=IntegerDigits[id];
  7.     dot=Dot[ids[[1;;17]],jym];(*前17位与校验码求内积*)
  8.     dot=Mod[dot,11];(*求余数*)
  9.     dot=Mod[12-dot,11];(*余数n,对应的最后一位编码是12-x*)
  10.     If[dot==ids[[18]],Return[True],Return[False]]
  11. ]
复制代码


我写的这个未能考虑最后一位是X的情况,
最后一位是X,应该如何考虑呢?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2019-4-19 15:13:56 | 显示全部楼层
这个容易,嵌套个特例啊
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2019-4-26 11:39:56 | 显示全部楼层
markfang2050 发表于 2019-4-19 15:13
这个容易,嵌套个特例啊

我自己用perl搞定了
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2019-4-26 22:05:47 | 显示全部楼层
mathematica 发表于 2019-4-26 11:39
我自己用perl搞定了

代码贴出啊,。C就可以。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-2-28 18:58:17 | 显示全部楼层
  1. (*
  2.   函数名称:IDCardValidate
  3.   函数功能:对输入的18位身份证号码进行合法性校验
  4.   输入参数:
  5.     id_String:表示输入的身份证号码,为字符串类型
  6.   返回值:
  7.     如果身份证号码合法,返回True;否则返回False
  8. *)
  9. IDCardValidate[id_String] :=
  10. Module[
  11.   {
  12.    idList,     (* 用于存储身份证号码前17位转换后的数字列表 *)
  13.    weights,    (* 身份证号码校验的加权因子列表 *)
  14.    sum,        (* 用于存储前17位数字与加权因子乘积的总和 *)
  15.    checkDigits,(* 对应不同余数的正确校验码列表 *)
  16.    remainder,  (* 总和对11取模后的余数 *)
  17.    expectedCheckDigit, (* 计算得出的预期校验码 *)
  18.    inputCheckDigit      (* 输入身份证号码的最后一位校验码 *)
  19.   },
  20.   (* 检查输入的身份证号码长度是否为18位,如果不是,直接返回False *)
  21.   If[StringLength[id] != 18, Return[False]];
  22.   (* 将身份证号码的前17位转换为数字列表 *)
  23.   idList = IntegerDigits[FromDigits[StringTake[id, {1, 17}]]];
  24.   (* 定义身份证号码校验的加权因子列表 *)
  25.   weights = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
  26.   (* 计算前17位数字与加权因子乘积的总和 *)
  27.   sum = Total[Thread[idList * weights]];
  28.   (* 计算总和对11取模后的余数 *)
  29.   remainder = Mod[sum, 11];
  30.   (* 定义对应不同余数的正确校验码列表 *)
  31.   checkDigits = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
  32.   (* 根据余数获取预期的校验码 *)
  33.   expectedCheckDigit = checkDigits[[remainder + 1]];
  34.   (* 获取输入身份证号码的最后一位校验码 *)
  35.   inputCheckDigit = StringTake[id, -1];
  36.   (* 如果输入的校验码是"X"或"x",统一转换为"X" *)
  37.   If[StringMatchQ[inputCheckDigit, "X" | "x"],
  38.    inputCheckDigit = "X"
  39.   ];
  40.   (* 比较预期校验码和输入校验码是否一致,一致则返回True,否则返回False *)
  41.   expectedCheckDigit == inputCheckDigit
  42. ]
复制代码


这是人工智能写的代码
看起来很不错
可读性非常强,还有详细注释与详细说明
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-2-28 21:13:19 | 显示全部楼层
nyy 发表于 2025-2-28 18:58
这是人工智能写的代码
看起来很不错
可读性非常强,还有详细注释与详细说明
  1. " 函数功能:此函数用于校验一个18位的身份证号码是否合法。
  2. " 依据中华人民共和国国家标准GB 11643-1999中规定的身份证号码编码规则进行校验。
  3. " 输入参数:
  4. "   a:idcard - 字符串类型,代表需要校验的身份证号码,必须为18位。
  5. " 返回参数:
  6. "   1 - 如果身份证号码合法,符合编码规则。
  7. "   0 - 如果身份证号码不合法,例如长度不为18位、字符不符合要求、校验码不正确等情况。
  8. function! ValidateIDCard(idcard) abort
  9.     " 检查身份证号码的长度是否为18位,如果不是则直接返回0,表示不合法
  10.     if len(a:idcard) != 18
  11.         return 0
  12.     endif
  13.     " 定义加权因子数组,用于计算身份证号码前17位的加权和
  14.     let factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
  15.     " 定义校验码数组,对应加权和取模11后的正确校验码
  16.     let parity = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
  17.     " 初始化加权和为0
  18.     let sum = 0
  19.     " 遍历身份证号码的前17位
  20.     for i in range(0, 16)
  21.         " 获取身份证号码当前位置的字符
  22.         let cur_char = a:idcard[i]
  23.         " 将当前字符转换为数字(如果不是数字则返回-1)
  24.         let digit = str2nr(cur_char)
  25.         " 如果转换失败(不是数字字符),则返回0,表示不合法
  26.         if digit == -1
  27.             return 0
  28.         endif
  29.         " 将当前数字乘以对应的加权因子,并累加到加权和中
  30.         let sum += digit * factor[i]
  31.     endfor
  32.     " 计算加权和对11取模的结果
  33.     let remainder = sum % 11
  34.     " 获取身份证号码的最后一位作为输入的校验码
  35.     let check_bit = a:idcard[17]
  36.     " 将输入的校验码转换为大写(如果是X的情况),以便和parity数组比较
  37.     if check_bit =~# 'x'
  38.         let check_bit = 'X'
  39.     endif
  40.     " 比较输入的校验码和计算得到的正确校验码是否一致
  41.     if check_bit == parity[remainder]
  42.         return 1
  43.     else
  44.         return 0
  45.     endif
  46. endfunction
复制代码


点评

nyy
26行到28行,str2nr函数用法错误,发生错误时,返回0  发表于 2025-3-5 13:35
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-2-28 21:13:56 | 显示全部楼层
  1. " 测试用例 1:合法的身份证号码,最后一位是数字
  2. let test_idcard1 = "110105194912310021"
  3. let result1 = ValidateIDCard(test_idcard1)
  4. echo "测试用例 1(合法,数字结尾):" . (result1 == 1? "通过" : "未通过")

  5. " 测试用例 2:合法的身份证号码,最后一位是 X
  6. let test_idcard2 = "11010519491231002X"
  7. let result2 = ValidateIDCard(test_idcard2)
  8. echo "测试用例 2(合法,X 结尾):" . (result2 == 1? "通过" : "未通过")

  9. " 测试用例 3:不合法的身份证号码,长度不足 18 位
  10. let test_idcard3 = "11010519491231002"
  11. let result3 = ValidateIDCard(test_idcard3)
  12. echo "测试用例 3(不合法,长度不足):" . (result3 == 0? "通过" : "未通过")

  13. " 测试用例 4:不合法的身份证号码,包含非数字非 X 字符
  14. let test_idcard4 = "11010519491231002A"
  15. let result4 = ValidateIDCard(test_idcard4)
  16. echo "测试用例 4(不合法,含非法字符):" . (result4 == 0? "通过" : "未通过")

  17. " 测试用例 5:不合法的身份证号码,校验码不正确
  18. let test_idcard5 = "110105194912310020"
  19. let result5 = ValidateIDCard(test_idcard5)
  20. echo "测试用例 5(不合法,校验码错误):" . (result5 == 0? "通过" : "未通过")
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-3-3 19:35:01 | 显示全部楼层
  1. (*
  2. 函数功能:
  3. 该函数用于全面检验中国身份证号码的有效性,包括校验码是否正确、出生年份是否在合理范围内(1900至2100年)、
  4. 月份和日期是否符合实际情况。中国身份证号码由17位数字本体码和1位校验码组成。
  5. 校验码的计算方法是:将前17位数字分别乘以对应的加权因子(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2),
  6. 然后将乘积相加,再对结果取模11,根据模值得到对应的校验码字符(模值为0对应X,模值为1对应1,以此类推),
  7. 最后与输入的身份证号码的最后一位进行比较,判断校验码是否正确。

  8. 函数用法:
  9. IsValidIDCard[cardNumber_String],传入一个字符串类型的身份证号码,函数将返回一个布尔值,
  10. 表示该身份证号码是否有效。

  11. 输入参数:
  12. - cardNumber:类型为字符串(String),意义是输入的中国身份证号码,长度应为18位。

  13. 返回值:
  14. - 类型为布尔值(Boolean),意义是如果输入的身份证号码完全有效,返回True;否则返回False。

  15. 示例:
  16. 1. IsValidIDCard["11010519491231002X"],返回True,因为这是一个完全有效的身份证号码。
  17. 2. IsValidIDCard["11010521011231002X"],返回False,因为出生年份超出合理范围。
  18. 3. IsValidIDCard["11010519491331002X"],返回False,因为月份不符合实际。
  19. 4. IsValidIDCard["11010519491232002X"],返回False,因为日期不符合实际。
  20. 5. IsValidIDCard["110105194912310021"],返回False,因为这是一个校验码错误的身份证号码。
  21. *)
  22. IsValidIDCard[cardNumber_String] :=
  23. Module[{weights = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2},
  24.         checkCodes = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"},
  25.         sum, remainder, checkDigit, year, month, day, dateValid},
  26.     If[StringLength[cardNumber] != 18,
  27.         Return[False]];
  28.    
  29.     (* 计算前17位数字与加权因子的乘积之和 *)
  30.     sum = 0;
  31.     For[i = 1, i <= 17, i++,
  32.         digit = FromDigits[StringTake[cardNumber, i]];
  33.         sum = sum + digit * weights[[i]];
  34.     ];
  35.     remainder = Mod[sum, 11];
  36.     checkDigit = StringTake[cardNumber, -1];
  37.    
  38.     (* 提取出生年份、月份和日期 *)
  39.     year = FromDigits[StringTake[cardNumber, {7, 10}]];
  40.     month = FromDigits[StringTake[cardNumber, {11, 12}]];
  41.     day = FromDigits[StringTake[cardNumber, {13, 14}]];
  42.    
  43.     (* 初始化日期有效性为True,然后根据条件修改 *)
  44.     dateValid = True;
  45.     If[year < 1900 || year > 2100, dateValid = False];
  46.     If[month < 1 || month > 12, dateValid = False];
  47.     If[(month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && (day < 1 || day > 31), dateValid = False];
  48.     If[(month == 4 || month == 6 || month == 9 || month == 11) && (day < 1 || day > 30), dateValid = False];
  49.     If[month == 2,
  50.         If[(Mod[year, 4] == 0 && Mod[year, 100] != 0) || Mod[year, 400] == 0,
  51.             If[(day < 1 || day > 29), dateValid = False],
  52.             If[(day < 1 || day > 28), dateValid = False]
  53.         ]
  54.     ];
  55.    
  56.     (* 综合校验码和日期有效性判断身份证是否有效 *)
  57.     dateValid && checkDigit === checkCodes[[remainder + 1]]
  58. ];

  59. (* 单元测试 *)
  60. (* 测试用例1:完全有效的身份证号码 *)
  61. Print["测试用例1:", IsValidIDCard["11010519491231002X"]];
  62. (* 测试用例2:校验码错误的身份证号码 *)
  63. Print["测试用例2:", IsValidIDCard["110105194912310021"]];
  64. (* 测试用例3:出生年份小于1900的身份证号码 *)
  65. Print["测试用例3:", IsValidIDCard["11010518991231002X"]];
  66. (* 测试用例4:出生年份大于2100的身份证号码 *)
  67. Print["测试用例4:", IsValidIDCard["11010521011231002X"]];
  68. (* 测试用例5:月份小于1的身份证号码 *)
  69. Print["测试用例5:", IsValidIDCard["11010519490031002X"]];
  70. (* 测试用例6:月份大于12的身份证号码 *)
  71. Print["测试用例6:", IsValidIDCard["11010519491331002X"]];
  72. (* 测试用例7:31天月份中日期大于31的身份证号码 *)
  73. Print["测试用例7:", IsValidIDCard["11010519490132002X"]];
  74. (* 测试用例8:30天月份中日期大于30的身份证号码 *)
  75. Print["测试用例8:", IsValidIDCard["11010519490431002X"]];
  76. (* 测试用例9:闰年2月日期大于29的身份证号码 *)
  77. Print["测试用例9:", IsValidIDCard["11010520000230002X"]];
  78. (* 测试用例10:非闰年2月日期大于28的身份证号码 *)
  79. Print["测试用例10:", IsValidIDCard["11010519010229002X"]];
复制代码

点评

nyy
36行代码有bug,digit = FromDigits[StringTake[cardNumber, i]];  发表于 2025-3-5 13:31
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-3-3 19:36:48 | 显示全部楼层
代码写的太好了。还生成测试用例。
还有注释有说明。
比人工写的好。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-3-5 13:31:06 | 显示全部楼层
本帖最后由 nyy 于 2025-3-5 13:41 编辑


代码写的是好,但是有bug。
  1. (*
  2. 函数功能:
  3. 该函数用于全面检验中国身份证号码的有效性,包括校验码是否正确、出生年份是否在合理范围内(1900至2100年)、
  4. 月份和日期是否符合实际情况。中国身份证号码由17位数字本体码和1位校验码组成。
  5. 校验码的计算方法是:将前17位数字分别乘以对应的加权因子(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2),
  6. 然后将乘积相加,再对结果取模11,根据模值得到对应的校验码字符(模值为0对应X,模值为1对应1,以此类推),
  7. 最后与输入的身份证号码的最后一位进行比较,判断校验码是否正确。
  8. 函数用法:
  9. IsValidIDCard[cardNumber_String],传入一个字符串类型的身份证号码,函数将返回一个布尔值,
  10. 表示该身份证号码是否有效。
  11. 输入参数:
  12. - cardNumber:类型为字符串(String,或者18位整数),意义是输入的中国身份证号码,长度应为18位。
  13. 返回值:
  14. - 类型为布尔值(Boolean),意义是如果输入的身份证号码完全有效,返回True;否则返回False。
  15. 示例:
  16. 1. IsValidIDCard["11010519491231002X"],返回True,因为这是一个完全有效的身份证号码。
  17. 2. IsValidIDCard["11010521011231002X"],返回False,因为出生年份超出合理范围。
  18. 3. IsValidIDCard["11010519491331002X"],返回False,因为月份不符合实际。
  19. 4. IsValidIDCard["11010519491232002X"],返回False,因为日期不符合实际。
  20. 5. IsValidIDCard["110105194912310021"],返回False,因为这是一个校验码错误的身份证号码。
  21. *)
  22. IsValidIDCard[_cardNumber] :=
  23. Module[{weights = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2},(*前17位权重*)
  24.         checkCodes = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"},(*0 1 2 3等余数所对应的校验码*)
  25.         sum, remainder, checkDigit, year, month, day, dateValid},
  26.     If[IntegerQ[cardNumber],cardNumber=ToString[cardNumber]];(*如果身份证号码是18位整数,则转化为字符串*)
  27.     If[StringLength[cardNumber] != 18,
  28.         Return[False]];
  29.     (* 计算前17位数字与加权因子的乘积之和 *)
  30.     sum = 0;
  31.     For[i = 1, i <= 17, i++,
  32.         digit = FromDigits[StringTake[cardNumber, {i}]];(*此处有bug,原本是StringTake[cardNumber,i],表示提取前i个字符,而此处需要是第i个字符*)
  33.         sum = sum + digit * weights[[i]];
  34.     ];
  35.     remainder = Mod[sum, 11];(*求余数*)
  36.     checkDigit = StringTake[cardNumber, -1];(*提取最后一位校验码*)
  37.     (* 提取出生年份、月份和日期 *)
  38.     year = FromDigits[StringTake[cardNumber, {7, 10}]];
  39.     month = FromDigits[StringTake[cardNumber, {11, 12}]];
  40.     day = FromDigits[StringTake[cardNumber, {13, 14}]];
  41.     (* 初始化日期有效性为True,然后根据条件修改 *)
  42.     dateValid = True;
  43.     If[year < 1900 || year > 2100, dateValid = False];
  44.     If[month < 1 || month > 12, dateValid = False];
  45.     If[(month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && (day < 1 || day > 31), dateValid = False];
  46.     If[(month == 4 || month == 6 || month == 9 || month == 11) && (day < 1 || day > 30), dateValid = False];
  47.     If[month == 2,
  48.         If[(Mod[year, 4] == 0 && Mod[year, 100] != 0) || Mod[year, 400] == 0,
  49.             If[(day < 1 || day > 29), dateValid = False],
  50.             If[(day < 1 || day > 28), dateValid = False]
  51.         ]
  52.     ];
  53.     (* 综合校验码和日期有效性判断身份证是否有效 *)
  54.     dateValid && (checkDigit === checkCodes[[remainder + 1]])
  55. ];

  56. (* 单元测试 *)
  57. (* 测试用例1:完全有效的身份证号码 *)
  58. Print["测试用例1:", IsValidIDCard["11010519491231002X"]];
  59. (* 测试用例2:校验码错误的身份证号码 *)
  60. Print["测试用例2:", IsValidIDCard["110105194912310021"]];
  61. (* 测试用例3:出生年份小于1900的身份证号码 *)
  62. Print["测试用例3:", IsValidIDCard["11010518991231002X"]];
  63. (* 测试用例4:出生年份大于2100的身份证号码 *)
  64. Print["测试用例4:", IsValidIDCard["11010521011231002X"]];
  65. (* 测试用例5:月份小于1的身份证号码 *)
  66. Print["测试用例5:", IsValidIDCard["11010519490031002X"]];
  67. (* 测试用例6:月份大于12的身份证号码 *)
  68. Print["测试用例6:", IsValidIDCard["11010519491331002X"]];
  69. (* 测试用例7:31天月份中日期大于31的身份证号码 *)
  70. Print["测试用例7:", IsValidIDCard["11010519490132002X"]];
  71. (* 测试用例8:30天月份中日期大于30的身份证号码 *)
  72. Print["测试用例8:", IsValidIDCard["11010519490431002X"]];
  73. (* 测试用例9:闰年2月日期大于29的身份证号码 *)
  74. Print["测试用例9:", IsValidIDCard["11010520000230002X"]];
  75. (* 测试用例10:非闰年2月日期大于28的身份证号码 *)
  76. Print["测试用例10:", IsValidIDCard["11010519010229002X"]];
复制代码


bug的原因,我已经写在代码里面了。
  1. digit = FromDigits[StringTake[cardNumber, i]];
复制代码

这个表示提取前i个字符
  1. digit = FromDigits[StringTake[cardNumber, {i}]];
复制代码

这个表示提取第i个字符,
看来人工智能真的不智能呀!
看起来是很正确的代码,结果还要我给你根除bug。

点评

nyy
难道是输入的参数不能被修改?不能被重新赋值?  发表于 2025-3-5 14:00
nyy
这个代码还是有bug  发表于 2025-3-5 13:58
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2025-3-26 14:04 , Processed in 0.052391 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表