Board logo

标题: 编程挑战-缺失的身份证号码 [打印本页]

作者: happy886rr    时间: 2017-4-10 15:23     标题: 编程挑战-缺失的身份证号码

本帖最后由 happy886rr 于 2017-4-10 15:36 编辑

[具有挑战性的问题]
  1. 这里给你一些不完整的身份证号码:6110251990062874?0(倒数第二位缺失,用?号替代),看你是否能根据前16位数码和最后一位校验码推测出完整的身份证号?
  2. 要求:不限编程语言,不限代码长度,只要能将缺失的?数字补全就行。
  3. 比如:
  4. 1509231988042396?9
  5. 3700001989091894?0
  6. 4313021981042877?1
  7. 5301021920050801?X
  8. 6110251990062874?0
  9. 补全后的效果是:
  10. 150923198804239619
  11. 370000198909189440
  12. 431302198104287701
  13. 53010219200508011X
  14. 611025199006287480
复制代码
.
.
.
以下是一些辅助信息,有助于你更快的解决该问题。
[身份证号码]
  1. 公民的身份证号码,是由前十七位数字码和最后一位校验码构成。其中第17位如果为奇数就是男性,为偶数是女性。
复制代码
[最后一位校验码是怎么确定的?]
  1. 将身份证号前17位数码分别乘以不同的系数,从第一位到第十七位所乘的系数分别为:7 、9 、10 、5 、8 、4 、2 、1 、6 、3 、7 、9 、10 、5 、8 、4 、2;将乘积相加,除以11,看余数是多少?
  2.     余数:0 、1、 2、 3、 4、 5、 6、 7、 8、 9、 10
  3. 对应的校验码:1 、0 、X 、9 、8 、7 、6 、5 、4 、3 、2
复制代码
[校验码计算示例]
  1. 某人身份证号码为53010219200508011X,首先我们得出前17位的乘积和(5*7)+(3*9)+(0*10)+(1*5)+(0*8)+(2*4)+(1*2)+(9*1)+(2*6)+(0*3)+(0*7)+(5*9)+(0*10)+(8*5)+(0*8)+(1*4)+(1*2)是189,然后用189除以11得出的结果是189/11=17余2,也就是说余数是2。最后通过对应规则就可以知道余数2对应的校验码是X。所以,可以判定这是一个正确的身份证号码。
复制代码
[我的代码实现]
cmd脚本
  1. @echo off
  2. call :start 1509231988042396?9
  3. call :start 3700001989091894?0
  4. call :start 4313021981042877?1
  5. call :start 5301021920050801?X
  6. call :start 6110251990062874?0
  7. pause
  8. exit
  9. :start <ID>
  10. setlocal
  11. set ID=%1
  12. set X=10
  13. set QI=79X584216379X58420
  14. for /l %%i in (0,1,15) do (
  15. call set/a "sum+=(%%ID:~%%i,1%%)*(%%QI:~%%i,1%%)"
  16. )
  17. set/a "r=(12-%ID:~-1%)%%11, n=(r+11-sum%%11), 1/(!(n&1))" 2>NUL ||set flag=1
  18. if %n% lss 11 (set/a "n+=11*flag") else (set/a "n-=11*flag")
  19. set/a "n>>=1"
  20. call echo %%ID:?=%n%%%
  21. endlocal
复制代码

作者: 523066680    时间: 2017-4-10 16:51

本帖最后由 523066680 于 2017-4-10 19:47 编辑

题目好,长见识(不好意思占楼了  
  1. my @list = qw/
  2. 1509231988042396?9
  3. 3700001989091894?0
  4. 4313021981042877?1
  5. 5301021920050801?X
  6. 6110251990062874?0/;
  7. my @num = qw(7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2);
  8. my %map;
  9. my $n = 0;
  10. grep { $map{ $_ } = $n++ } qw(1 0 X 9 8 7 6 5 4 3 2);
  11. grep { print func($_) , "\n" } @list;
  12. sub func
  13. {
  14. my $s = shift;
  15. my $sum = 0;
  16. my $last = $map{ substr($s, -1, 1) };
  17. my $code;
  18. grep { $sum += substr($s, $_, 1) * $num[$_] } ( 0 .. 15 );
  19. grep { $code = $_ if ( ($_ * 2 + $sum) % 11 == $last) } ( 0..9 );
  20. $s =~s/\?/$code/;
  21. return $s;
  22. }
复制代码
根据 happy 的提醒,加一个补充,通过判断和计算求出缺失的数字而非遍历
  1. my @list = qw/
  2. 1509231988042396?9
  3. 3700001989091894?0
  4. 4313021981042877?1
  5. 5301021920050801?X
  6. 6110251990062874?0/;
  7. my $n = 0;
  8. my %map;
  9. my @num = qw(7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2);
  10. grep { $map{ $_ } = $n++ } qw(1 0 X 9 8 7 6 5 4 3 2);
  11. grep { print func($_) , "\n" } @list;
  12. sub func
  13. {
  14.     my $s = shift;
  15.     my $sum = 0;
  16.     my $last = $map{ substr($s, -1, 1) };
  17.     my $code;
  18.     grep { $sum += substr($s, $_, 1) * $num[$_] } ( 0 .. 15 );
  19.     $test = $sum % 11;
  20.     $code = ( $last - $test ) / 2;
  21.     $code += 11/2 if ( $code < 0 );
  22.     $code += 11/2 if ( int($code) != $code );
  23.     $s =~s/\?/$code/;
  24.     return $s;
  25. }
复制代码

作者: pcl_test    时间: 2017-4-10 17:54

本帖最后由 pcl_test 于 2017-4-10 18:25 编辑
  1. @echo off
  2. powershell ^
  3.     $a='^
  4.         1509231988042396?9^
  5.         3700001989091894?0^
  6.         4313021981042877?1^
  7.         5301021920050801?X^
  8.         6110251990062874?0';^
  9.     $n=@{0=7;1=9;2=10;3=5;4=8;5=4;6=2;7=1;8=6;9=3;10=7;11=9;12=10;13=5;14=8;15=4};^
  10.     $m=@{'1'=0;'0'=1;'X'=2;'9'=3;'8'=4;'7'=5;'6'=6;'5'=7;'4'=8;'3'=9;'2'=10};^
  11.     $a.trim() -split '\s+'^|%%{^
  12.         $r=$_.trim();$s=0;^
  13.         0..15^|%%{$s+=1*$r[$_].ToString()*$n[$_]};^
  14.         $t=0..9^|?{((($s-$m[''+$r[-1]])+2*$_)%%11) -eq 0};^
  15.         $r.replace('?',$t);^
  16.     }
  17. pause
复制代码

作者: happy886rr    时间: 2017-4-10 18:38

回复 2# 523066680
方法很多,最简单的还是0~9一个一个试,但是那样得用两次循环,我是用set/a逆推出数字,因此这道题最少只需for一次。
作者: 523066680    时间: 2017-4-10 18:43

本帖最后由 523066680 于 2017-4-10 18:48 编辑

回复 4# happy886rr


    想过, SUM1 + 2*n = LastNumber,通过 SUM1的余数 和 LastNumber映射的余数进行计算,可以得到 n ,不过我猜我用的方案可能不够直接,
需要做 if 判断, 所以还是先粗暴循环了(一般都是先贴,后面再改 )
作者: happy886rr    时间: 2017-4-10 18:48

本帖最后由 happy886rr 于 2017-4-10 18:51 编辑

回复 5# 523066680
是个同余原理,三种情况,比从0~9试10次要快点。这个题身份证只是缺失一位,如果缺失两位,在知道性别的话,也能算出来,但是难度太大了。
作者: a20150604    时间: 2017-4-10 21:30

从校验码计算应得余数 -> 减去前16位已得余数, 得余数偏差, 偏差为负则 加 11, 得非负余偏差后, 判断奇偶, 非负余偏差是奇数就加11, -> 最后除以 2(第17位的系数) 商就是第17位的数字
  1. @echo off & setlocal enableDelayedExpansion
  2. for %%i in (
  3. 1509231988042396#9
  4. 3700001989091894#0
  5. 4313021981042877#1
  6. 5301021920050801#X
  7. 6110251990062874#0
  8. ) do (
  9.     set "d=%%i"
  10.     set "c=!d:~-1!"
  11.     set /a "c=!c:x=10!,  t= c - 2>>31, r=t&(c^^1)|~t&(12-c), dr= r - ( (!d:~0,1!+!d:~10,1!)*7+(!d:~1,1!+!d:~11,1!)*9+(!d:~2,1!+!d:~12,1!)*10+(!d:~3,1!+!d:~13,1!)*5+(!d:~4,1!+!d:~14,1!)*8+(!d:~5,1!+!d:~15,1!)*4+!d:~6,1!*2+!d:~7,1!+!d:~8,1!*6+!d:~9,1!*3 ) %% 11, u=dr+(dr>>31&11), v=(u+(u&1)*11)/2"
  12.     echo;!d:~0,-2!!v!!d:~-1!
  13. )
  14. pause
复制代码

作者: 老刘1号    时间: 2017-4-10 22:14

本帖最后由 老刘1号 于 2017-4-10 22:37 编辑

存批,暴力解法
  1. '&@(cls&cscript -e:vbscript -nologo "%~0"&pause&exit)
  2. Dim ID_Card(5)
  3. ID_Card(1) = "1509231988042396?9"
  4. ID_Card(2) = "3700001989091894?0"
  5. ID_Card(3) = "4313021981042877?1"
  6. ID_Card(4) = "5301021920050801?X"
  7. ID_Card(5) = "6110251990062874?0"
  8. Dim NUMBER_Multiplie(17)
  9. NUMBER_Multiplie(1) = 7
  10. NUMBER_Multiplie(2) = 9
  11. NUMBER_Multiplie(3) =10
  12. NUMBER_Multiplie(4) = 5
  13. NUMBER_Multiplie(5) = 8
  14. NUMBER_Multiplie(6) = 4
  15. NUMBER_Multiplie(7) = 2
  16. NUMBER_Multiplie(8) = 1
  17. NUMBER_Multiplie(9) = 6
  18. NUMBER_Multiplie(10)= 3
  19. NUMBER_Multiplie(11)= 7
  20. NUMBER_Multiplie(12)= 9
  21. NUMBER_Multiplie(13)=10
  22. NUMBER_Multiplie(14)= 5
  23. NUMBER_Multiplie(15)= 8
  24. NUMBER_Multiplie(16)= 4
  25. NUMBER_Multiplie(17)= 2
  26. Dim Check_Code(10)
  27. Check_Code(0) = 1
  28. Check_Code(1) = 0
  29. Check_Code(2) ="X"
  30. Check_Code(3) = 9
  31. Check_Code(4) = 8
  32. Check_Code(5) = 7
  33. Check_Code(6) = 6
  34. Check_Code(7) = 5
  35. Check_Code(8) = 4
  36. Check_Code(9) = 3
  37. Check_Code(10)= 2
  38. Rem 代码开始:
  39. For NO = 1 To 5
  40. Result = Empty
  41. Calculate = 0
  42. For Multiplie = 1 To 16
  43. Calculate = Calculate + Mid(ID_Card(NO),Multiplie,1) * NUMBER_Multiplie(Multiplie)
  44. Next
  45. For Test = 0 To 10
  46. If CStr(Check_Code((Calculate + Test * NUMBER_Multiplie(17)) Mod 11)) = Mid(ID_Card(NO),18,1) Then Result = Test
  47. Next
  48. Result=Left(ID_Card(NO),16)&Result&Right(ID_Card(NO),1)
  49. WScript.Echo ID_Card(NO) & " -- > " & Result
  50. next
复制代码

作者: terse    时间: 2017-4-11 10:36

多个循环了
  1. @echo off & setlocal enabledelayedexpansion
  2. set "s=10X98765432"
  3. set "sx=79a584216379a5842"
  4. for /l %%i in (0,1,10) do set #!s:~%%i,1!=%%i
  5. for /f "delims=#" %%i in ('findstr /ib # %0') do (
  6.     set id=%%i
  7.     set e=!id:~-1!
  8.     set n=0&set "?="
  9.     for /l %%k in (0,1,16) do (
  10.         set /a n+=!id:~%%k,1!*0x!sx:~%%k,1!
  11.         set "!id:~%%k,1!=!sx:~%%k,1!"
  12.     )
  13.     set /a n%%=11
  14.     if defined ? for /l %%i in (0,1,9) do (
  15.        set/a "x=(%%i*?+n) %% 11"
  16.        for %%j in (!e!) do if !x! equ !#%%j! set "id=!id:?=%%i!"
  17.     )
  18.     echo;!id!
  19. )
  20. pause & exit
  21. #15?923198804239619
  22. #3700001989091894?0
  23. #4313021981042877?1
  24. #5301021920050801?X
  25. #611?25199006287480
复制代码

作者: taofan712    时间: 2017-4-11 16:09

  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set idbox=1509231988042396?9;3700001989091894?0;4313021981042877?1;5301021920050801?X;6110251990062874?0
  4. set muli=7 、9 、10 、5 、8 、4 、2 、1 、6 、3 、7 、9 、10 、5 、8 、4 、2
  5. set idbox=%idbox:?=#%
  6. set muli=%muli:10=t%
  7. set muli=%muli: 、=%
  8. set /a t=10
  9. set yushu=0123456789t
  10. set code=10X98765432
  11. for /l %%i in (0 1 10) do call set ".%%code:~%%i,1%%=%%yushu:~%%i,1%%"
  12. for %%a in (%idbox%) do (
  13. set id=%%a
  14. set/p=!id:#=?!<nul
  15. for /l %%b in (0 1 15) do (
  16. call set /a "sum+=%%id:~%%b,1%%*%%muli:~%%b,1%%"
  17. )
  18. for %%c in (0 1 2 3 4 5 6 7 8 9) do (
  19. if not defined yes (
  20. set /a t_sum=sum+%%c*2
  21. set /a t_mod=t_sum%%11
  22. set t_mod=!t_mod:10=t!
  23. for /f "delims==" %%d in ('set .^|findstr /e !t_mod!') do (
  24. if "%%d"==".!id:~-1!" (
  25. echo;         应该是:!id:#=%%c!
  26. set yes=1
  27. )
  28. set "t_sum=" & set "t_mod="
  29. )
  30. )
  31. )
  32. set "sum="
  33. set "yes="
  34. )
  35. echo;over&pause>nul&exit /b
复制代码





欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2