找回密码
 欢迎注册
楼主: mathematica

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

[复制链接]
发表于 2025-3-5 13:55:00 | 显示全部楼层
nyy 发表于 2025-3-5 13:31
代码写的是好,但是有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[cardID],传入一个字符串类型的身份证号码,函数将返回一个布尔值,
  10. 表示该身份证号码是否有效。
  11. 输入参数:
  12. - cardID:类型为字符串(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[cardID_] :=
  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,cardNumber},
  26.     If[IntegerQ[cardID],cardNumber=ToString[cardID],cardNumber=cardID];(*如果身份证号码是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. ];
复制代码


根除身份证号码是整数的bug

点评

nyy
代码是写的不错,不过实在是太长了!  发表于 2025-3-5 15:04
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-3-5 16:18:43 | 显示全部楼层
  1. " 函数功能:
  2. " 该函数用于检验身份证号码的校验码是否正确,并且检查身份证号码中包含的出生日期是否合法。
  3. " 合法的年份范围在1900年到2500年之间,同时会检查每个月的天数是否符合实际情况(如2月在平年有28天,闰年有29天等)。
  4. " 函数用法:
  5. " 调用函数时,传入一个字符串类型的身份证号码作为参数,函数会返回一个布尔值,
  6. " 如果身份证号码校验码正确且日期合法则返回 1,否则返回 0。
  7. " 输入参数:
  8. "   id_card_number:字符串类型,代表输入的身份证号码,长度应为18位。
  9. " 返回值:
  10. "   返回值为数值类型(0 或 1)。1 表示身份证号码校验码正确且日期合法,0 表示校验码错误或日期不合法。
  11. " 输入值返回值例子:
  12. " 例子1:输入一个正确的身份证号码(校验码正确且日期合法),函数返回 1。
  13. " 例子2:输入一个校验码错误的身份证号码,函数返回 0。
  14. " 例子3:输入一个日期不合法(年份不在1900到2500之间)的身份证号码,函数返回 0。
  15. " 例子4:输入一个日期不合法(如2月有30天)的身份证号码,函数返回 0。
  16. function! CheckIDCard(id_card_number)
  17.     " 定义权重数组,用于计算校验码
  18.     let weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
  19.     " 定义校验码字符数组,对应不同的校验码值,兼容x和X
  20.     let check_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
  21.     " 检查身份证号码长度是否为18位
  22.     if strlen(a:id_card_number) != 18
  23.         return 0
  24.     endif
  25.     " 计算校验码
  26.     let sum = 0
  27.     for i in range(0, 16)
  28.         let num = str2nr(substitute(a:id_card_number[i], '\D', '', ''))
  29.         let sum += num * weights[i]
  30.     endfor
  31.     let check_index = sum % 11
  32.     let check_code = check_codes[check_index]
  33.     " 转换输入身份证号码最后一位为大写,以便和校验码比较
  34.     let input_check_code = toupper(a:id_card_number[17])
  35.     " 检查校验码是否正确
  36.     if check_code != input_check_code
  37.         return 0
  38.     endif
  39.     " 提取身份证号码中的年份、月份、日期信息
  40.     let year_str = a:id_card_number[6:9]
  41.     let year = str2nr(year_str)
  42.     let month_str = a:id_card_number[10:11]
  43.     let month = str2nr(month_str)
  44.     let day_str = a:id_card_number[12:13]
  45.     let day = str2nr(day_str)
  46.     " 检查年份是否在合法范围内
  47.     if year < 1900 || year > 2500
  48.         return 0
  49.     endif
  50.     " 检查月份是否在1到12之间
  51.     if month < 1 || month > 12
  52.         return 0
  53.     endif
  54.     " 定义每个月的天数数组,2月先按平年算
  55.     let days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
  56.     " 判断是否为闰年,如果是,2月有29天
  57.     if (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
  58.         let days_in_month[1] = 29
  59.     endif
  60.     " 检查日期是否在合法范围内
  61.     if day < 1 || day > days_in_month[month - 1]
  62.         return 0
  63.     endif
  64.     " 如果校验码正确且日期合法,返回 1
  65.     return 1
  66. endfunction
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-3-5 22:03:23 | 显示全部楼层
本帖最后由 nyy 于 2025-3-5 22:04 编辑

  1. idCardVerify[card_String] :=
  2.   Module[{weights = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2},
  3.           checkCodes = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"}},
  4.     If[StringLength[card] != 18, False,
  5.       Total[MapThread[Times, {StringTake[card, -17], weights}]] //
  6.        Mod[#, 11] & // (checkCodes[[# + 1]] == StringTake[card, -1]) &
  7.     ]
  8.   ]
复制代码


人工智能写的代码真短,但是我不知道他写的对不对

  1. idCardVerify[card_String] :=
  2.   Module[{weights = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2},
  3.           checkCodes = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"}},
  4.     If[StringLength[card]!= 18, False,
  5.       Total[MapThread[Times, {StringTake[card, {1, 17}], weights}]] //
  6.        Mod[#, 11] & // (checkCodes[[# + 1]] == StringTake[card, -1]) &
  7.     ]
  8.   ]
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-3-5 22:13:34 | 显示全部楼层
IDCheck[id_String]:=With[{check=Mod[11-Mod[Total[ToExpression[Characters[id[[;;17]]]]*{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2},11],11]},check==Switch[id[[18]],"X",10,_,ToExpression[id[[18]]]]]

人工智能写的代码都让人讨厌
这个是deepseek写的

点评

nyy
日你妈,这代码写的括号都不匹配  发表于 2025-3-6 08:44
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-3-5 22:27:02 | 显示全部楼层
nyy 发表于 2025-3-5 22:13
IDCheck[id_String]:=With[{check=Mod[11-Mod[Total[ToExpression[Characters[id[[;;17]]]]*{7,9,10,5,8,4, ...

第1行应该是12-,而不是11-,人工智能就喜欢制造bug
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-3-5 22:37:30 | 显示全部楼层
nyy 发表于 2025-3-5 22:27
第1行应该是12-,而不是11-,人工智能就喜欢制造bug

人工智能真的有些智能,
我基本上每天都用人工智能
哪怕是和人工智能聊聊天
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-3-6 09:02:03 | 显示全部楼层
nyy 发表于 2025-3-5 22:13
IDCheck[id_String]:=With[{check=Mod[11-Mod[Total[ToExpression[Characters[id[[;;17]]]]*{7,9,10,5,8,4, ...
  1. IDCheck[id_String]:=With[{check=Mod[12-Total[ToExpression@Characters[id][[1;;17]]*{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2}],11]},check==Switch[Characters[id][[18]],"X",10,_,ToExpression[Characters[id][[18]]]]]
复制代码


这个是根除代码后的代码,还优化了一下
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-3-6 10:55:18 | 显示全部楼层
nyy 发表于 2025-3-6 09:02
这个是根除代码后的代码,还优化了一下
  1. IDCheck[id_String] := Module[
  2.   {weights, checkCode, sum, remainder, calculatedCheck,idlist},
  3.   (* 定义权重系数 *)
  4.   weights = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
  5.   (*形成18位字符列表*)
  6.   idlist=Characters[id];
  7.   (* 提取前17位并转换为数字列表 *)
  8.   sum = Total[ToExpression[idlist[[1;;17]]]*weights];
  9.   (* 计算余数 *)
  10.   remainder = Mod[sum,11];
  11.   (* 计算校验码 *)
  12.   calculatedCheck = Mod[12-remainder, 11];
  13.   (* 处理最后一位校验码(如果是X,则转换为10) *)
  14.   checkCode=Switch[idlist[[18]],
  15.     "X", 10,
  16.     "x", 10,(*小写字母也加上*)
  17.     _, ToExpression[idlist[[18]]]
  18.   ];
  19.   (* 比较计算值与实际校验码 *)
  20.   calculatedCheck == checkCode
  21. ]
复制代码

deepseek写的代码,被我根除bug,以及优化后的代码!
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-3-6 15:16:12 | 显示全部楼层
人工智能写的代码,经过我的稍微修改与美化与完善,加上生成的测试用例(人工智能生成的测试用例,居然也用错误!)

  1. " 函数功能:
  2. " 该函数用于检验身份证号码的校验码是否正确,并且检查身份证号码中包含的出生日期是否合法。
  3. " 合法的年份范围在1900年到2500年之间,同时会检查每个月的天数是否符合实际情况(如2月在平年有28天,闰年有29天等)。
  4. " 函数用法:
  5. " 调用函数时,传入一个字符串类型的身份证号码作为参数,函数会返回一个布尔值,
  6. " 如果身份证号码校验码正确且日期合法则返回 1,否则返回 0。
  7. " 输入参数:
  8. "   id_card_number:字符串类型,代表输入的身份证号码,长度应为18位。
  9. " 返回值:
  10. "   返回值为数值类型(0 或 1)。1 表示身份证号码校验码正确且日期合法,0 表示校验码错误或日期不合法。
  11. " 输入值返回值例子:
  12. " 例子1:输入一个正确的身份证号码(校验码正确且日期合法),函数返回 1。
  13. " 例子2:输入一个校验码错误的身份证号码,函数返回 0。
  14. " 例子3:输入一个日期不合法(年份不在1900到2500之间)的身份证号码,函数返回 0。
  15. " 例子4:输入一个日期不合法(如2月有30天)的身份证号码,函数返回 0。
  16. function! CheckIDCard(id_card_number)
  17.     "默认的信息输出间隔符号
  18.     echo "-------------------------------------------------\n"
  19.     "先给出默认返回值1,如果有错误,则修改成0
  20.     let out=1
  21.     " 定义权重数组,用于计算校验码
  22.     let weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
  23.     " 定义校验码字符数组,对应不同的校验码值,兼容x和X
  24.     let check_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
  25.     " 检查身份证号码长度是否为18位
  26.     if strlen(a:id_card_number) != 18
  27.         echo "身份证号码必须18位字符串\n"
  28.         let out=0
  29.         return out
  30.     endif
  31.     " 计算校验码
  32.     let sum = 0
  33.     for i in range(0, 16)
  34.         let num = str2nr(a:id_card_number[i])
  35.         let sum += num * weights[i]
  36.     endfor
  37.     let check_index = sum % 11
  38.     let check_code = check_codes[check_index]
  39.     " 转换输入身份证号码最后一位为大写,以便和校验码比较
  40.     let input_check_code = toupper(a:id_card_number[17])
  41.     " 检查校验码是否正确
  42.     if check_code != input_check_code
  43.         echo "第18位校验码应该是".check_code."\n"
  44.         let out=0
  45.     endif
  46.     " 提取身份证号码中的年份、月份、日期信息
  47.     let year = str2nr(a:id_card_number[6:9])
  48.     let month = str2nr(a:id_card_number[10:11])
  49.     let day = str2nr(a:id_card_number[12:13])
  50.     " 检查年份是否在合法范围内
  51.     if year < 1900 || year > 2500
  52.         echo "年份需要在1900-2500年之间\n"
  53.         let out=0
  54.     endif
  55.     " 检查月份是否在1到12之间
  56.     if month < 1 || month > 12
  57.         echo "月份不合法!\n"
  58.         let out=0
  59.     endif
  60.     " 定义每个月的天数数组,2月先按平年算
  61.     let days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
  62.     " 判断是否为闰年,如果是,2月有29天
  63.     if (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
  64.         let days_in_month[1] = 29
  65.     endif
  66.     " 检查日期是否在合法范围内
  67.     if day < 1 || day > days_in_month[month - 1]
  68.         echo "日期不合法!\n"
  69.         let out=0
  70.     endif
  71.     " 如果校验码正确且日期合法,返回 1
  72.     return out
  73. endfunction

  74. " 测试用例 1:正确的身份证号码   预期输出: 1
  75. let test_id1 = '11010519491231002X'
  76. echo CheckIDCard(test_id1)

  77. " 测试用例 2:校验码错误的身份证号码   预期输出: 0
  78. let test_id2 = '110105194912310021'
  79. echo CheckIDCard(test_id2)

  80. " 测试用例 3:年份小于 1900 的身份证号码   预期输出: 0
  81. let test_id3 = '11010518991231002X'
  82. echo CheckIDCard(test_id3)

  83. " 测试用例 4:年份大于 2500 的身份证号码   预期输出: 0
  84. let test_id4 = '11010525011231002X'
  85. echo CheckIDCard(test_id4)

  86. " 测试用例 5:身份证号码长度错误   预期输出: 0
  87. let test_id5 = '11010519491231002'
  88. echo CheckIDCard(test_id5)

  89. " 测试用例 6:2月有29天的闰年身份证号码   预期输出: 0
  90. let test_id6 = '310109202002290011'
  91. echo CheckIDCard(test_id6)

  92. " 测试用例 7:2月有28天的平年身份证号码   预期输出: 0
  93. let test_id7 = '310109202102280011'
  94. echo CheckIDCard(test_id7)

  95. " 测试用例 8:2月有30天的非法日期身份证号码   预期输出: 0
  96. let test_id8 = '310109202102300011'
  97. echo CheckIDCard(test_id8)

  98. " 测试用例 9:月份为0的非法日期身份证号码   预期输出: 0
  99. let test_id9 = '310109202100300011'
  100. echo CheckIDCard(test_id9)

  101. " 测试用例 10:日期为0的非法日期身份证号码   预期输出: 0
  102. let test_id10 = '310109202101000011'
  103. echo CheckIDCard(test_id10)
复制代码

点评

nyy
再检查一下匹配模式  发表于 2025-3-6 22:39
nyy
用vim运行!  发表于 2025-3-6 15:17
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2025-3-8 13:18:20 | 显示全部楼层
nyy 发表于 2025-3-6 15:16
人工智能写的代码,经过我的稍微修改与美化与完善,加上生成的测试用例(人工智能生成的测试用例,居然也用 ...

还可以继续优化!把所有的错误信息连接成一个字符串,这样方便调试测试!

点评

nyy
还有在前面用正则匹配测试一下  发表于 2025-3-8 13:18
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

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

GMT+8, 2025-3-26 13:57 , Processed in 0.037178 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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