标题: 编程挑战-缺失的身份证号码 [打印本页]
作者: happy886rr 时间: 2017-4-10 15:23 标题: 编程挑战-缺失的身份证号码
本帖最后由 happy886rr 于 2017-4-10 15:36 编辑
[具有挑战性的问题]- 这里给你一些不完整的身份证号码:6110251990062874?0(倒数第二位缺失,用?号替代),看你是否能根据前16位数码和最后一位校验码推测出完整的身份证号?
- 要求:不限编程语言,不限代码长度,只要能将缺失的?数字补全就行。
-
- 比如:
- 1509231988042396?9
- 3700001989091894?0
- 4313021981042877?1
- 5301021920050801?X
- 6110251990062874?0
-
- 补全后的效果是:
- 150923198804239619
- 370000198909189440
- 431302198104287701
- 53010219200508011X
- 611025199006287480
复制代码
.
.
.
以下是一些辅助信息,有助于你更快的解决该问题。
[身份证号码]- 公民的身份证号码,是由前十七位数字码和最后一位校验码构成。其中第17位如果为奇数就是男性,为偶数是女性。
复制代码
[最后一位校验码是怎么确定的?]- 将身份证号前17位数码分别乘以不同的系数,从第一位到第十七位所乘的系数分别为:7 、9 、10 、5 、8 、4 、2 、1 、6 、3 、7 、9 、10 、5 、8 、4 、2;将乘积相加,除以11,看余数是多少?
- 余数:0 、1、 2、 3、 4、 5、 6、 7、 8、 9、 10
- 对应的校验码:1 、0 、X 、9 、8 、7 、6 、5 、4 、3 、2
复制代码
[校验码计算示例]- 某人身份证号码为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脚本- @echo off
- call :start 1509231988042396?9
- call :start 3700001989091894?0
- call :start 4313021981042877?1
- call :start 5301021920050801?X
- call :start 6110251990062874?0
- pause
- exit
-
- :start <ID>
- setlocal
- set ID=%1
- set X=10
- set QI=79X584216379X58420
- for /l %%i in (0,1,15) do (
- call set/a "sum+=(%%ID:~%%i,1%%)*(%%QI:~%%i,1%%)"
- )
- set/a "r=(12-%ID:~-1%)%%11, n=(r+11-sum%%11), 1/(!(n&1))" 2>NUL ||set flag=1
- if %n% lss 11 (set/a "n+=11*flag") else (set/a "n-=11*flag")
- set/a "n>>=1"
- call echo %%ID:?=%n%%%
- endlocal
复制代码
作者: 523066680 时间: 2017-4-10 16:51
本帖最后由 523066680 于 2017-4-10 19:47 编辑
题目好,长见识(不好意思占楼了 - my @list = qw/
- 1509231988042396?9
- 3700001989091894?0
- 4313021981042877?1
- 5301021920050801?X
- 6110251990062874?0/;
-
- my @num = qw(7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2);
- my %map;
- my $n = 0;
- grep { $map{ $_ } = $n++ } qw(1 0 X 9 8 7 6 5 4 3 2);
-
- grep { print func($_) , "\n" } @list;
-
- sub func
- {
- my $s = shift;
- my $sum = 0;
- my $last = $map{ substr($s, -1, 1) };
- my $code;
-
- grep { $sum += substr($s, $_, 1) * $num[$_] } ( 0 .. 15 );
- grep { $code = $_ if ( ($_ * 2 + $sum) % 11 == $last) } ( 0..9 );
-
- $s =~s/\?/$code/;
- return $s;
- }
复制代码
根据 happy 的提醒,加一个补充,通过判断和计算求出缺失的数字而非遍历- my @list = qw/
- 1509231988042396?9
- 3700001989091894?0
- 4313021981042877?1
- 5301021920050801?X
- 6110251990062874?0/;
-
- my $n = 0;
- my %map;
- my @num = qw(7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2);
- grep { $map{ $_ } = $n++ } qw(1 0 X 9 8 7 6 5 4 3 2);
- grep { print func($_) , "\n" } @list;
-
- sub func
- {
- my $s = shift;
- my $sum = 0;
- my $last = $map{ substr($s, -1, 1) };
- my $code;
-
- grep { $sum += substr($s, $_, 1) * $num[$_] } ( 0 .. 15 );
- $test = $sum % 11;
- $code = ( $last - $test ) / 2;
- $code += 11/2 if ( $code < 0 );
- $code += 11/2 if ( int($code) != $code );
-
- $s =~s/\?/$code/;
- return $s;
- }
复制代码
作者: pcl_test 时间: 2017-4-10 17:54
本帖最后由 pcl_test 于 2017-4-10 18:25 编辑
- @echo off
- powershell ^
- $a='^
- 1509231988042396?9^
- 3700001989091894?0^
- 4313021981042877?1^
- 5301021920050801?X^
- 6110251990062874?0';^
- $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};^
- $m=@{'1'=0;'0'=1;'X'=2;'9'=3;'8'=4;'7'=5;'6'=6;'5'=7;'4'=8;'3'=9;'2'=10};^
- $a.trim() -split '\s+'^|%%{^
- $r=$_.trim();$s=0;^
- 0..15^|%%{$s+=1*$r[$_].ToString()*$n[$_]};^
- $t=0..9^|?{((($s-$m[''+$r[-1]])+2*$_)%%11) -eq 0};^
- $r.replace('?',$t);^
- }
- 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位的数字- @echo off & setlocal enableDelayedExpansion
- for %%i in (
- 1509231988042396#9
- 3700001989091894#0
- 4313021981042877#1
- 5301021920050801#X
- 6110251990062874#0
- ) do (
- set "d=%%i"
- set "c=!d:~-1!"
- 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"
- echo;!d:~0,-2!!v!!d:~-1!
- )
- pause
复制代码
作者: 老刘1号 时间: 2017-4-10 22:14
本帖最后由 老刘1号 于 2017-4-10 22:37 编辑
存批,暴力解法- '&@(cls&cscript -e:vbscript -nologo "%~0"&pause&exit)
-
- Dim ID_Card(5)
- ID_Card(1) = "1509231988042396?9"
- ID_Card(2) = "3700001989091894?0"
- ID_Card(3) = "4313021981042877?1"
- ID_Card(4) = "5301021920050801?X"
- ID_Card(5) = "6110251990062874?0"
-
- Dim NUMBER_Multiplie(17)
- NUMBER_Multiplie(1) = 7
- NUMBER_Multiplie(2) = 9
- NUMBER_Multiplie(3) =10
- NUMBER_Multiplie(4) = 5
- NUMBER_Multiplie(5) = 8
- NUMBER_Multiplie(6) = 4
- NUMBER_Multiplie(7) = 2
- NUMBER_Multiplie(8) = 1
- NUMBER_Multiplie(9) = 6
- NUMBER_Multiplie(10)= 3
- NUMBER_Multiplie(11)= 7
- NUMBER_Multiplie(12)= 9
- NUMBER_Multiplie(13)=10
- NUMBER_Multiplie(14)= 5
- NUMBER_Multiplie(15)= 8
- NUMBER_Multiplie(16)= 4
- NUMBER_Multiplie(17)= 2
-
- Dim Check_Code(10)
- Check_Code(0) = 1
- Check_Code(1) = 0
- Check_Code(2) ="X"
- Check_Code(3) = 9
- Check_Code(4) = 8
- Check_Code(5) = 7
- Check_Code(6) = 6
- Check_Code(7) = 5
- Check_Code(8) = 4
- Check_Code(9) = 3
- Check_Code(10)= 2
-
- Rem 代码开始:
- For NO = 1 To 5
- Result = Empty
- Calculate = 0
- For Multiplie = 1 To 16
- Calculate = Calculate + Mid(ID_Card(NO),Multiplie,1) * NUMBER_Multiplie(Multiplie)
- Next
- For Test = 0 To 10
- If CStr(Check_Code((Calculate + Test * NUMBER_Multiplie(17)) Mod 11)) = Mid(ID_Card(NO),18,1) Then Result = Test
- Next
- Result=Left(ID_Card(NO),16)&Result&Right(ID_Card(NO),1)
- WScript.Echo ID_Card(NO) & " -- > " & Result
- next
-
复制代码
作者: terse 时间: 2017-4-11 10:36
多个循环了- @echo off & setlocal enabledelayedexpansion
- set "s=10X98765432"
- set "sx=79a584216379a5842"
- for /l %%i in (0,1,10) do set #!s:~%%i,1!=%%i
- for /f "delims=#" %%i in ('findstr /ib # %0') do (
- set id=%%i
- set e=!id:~-1!
- set n=0&set "?="
- for /l %%k in (0,1,16) do (
- set /a n+=!id:~%%k,1!*0x!sx:~%%k,1!
- set "!id:~%%k,1!=!sx:~%%k,1!"
- )
- set /a n%%=11
- if defined ? for /l %%i in (0,1,9) do (
- set/a "x=(%%i*?+n) %% 11"
- for %%j in (!e!) do if !x! equ !#%%j! set "id=!id:?=%%i!"
- )
- echo;!id!
- )
-
- pause & exit
-
- #15?923198804239619
- #3700001989091894?0
- #4313021981042877?1
- #5301021920050801?X
- #611?25199006287480
复制代码
作者: taofan712 时间: 2017-4-11 16:09
- @echo off
- setlocal enabledelayedexpansion
- set idbox=1509231988042396?9;3700001989091894?0;4313021981042877?1;5301021920050801?X;6110251990062874?0
- set muli=7 、9 、10 、5 、8 、4 、2 、1 、6 、3 、7 、9 、10 、5 、8 、4 、2
- set idbox=%idbox:?=#%
- set muli=%muli:10=t%
- set muli=%muli: 、=%
- set /a t=10
- set yushu=0123456789t
- set code=10X98765432
- for /l %%i in (0 1 10) do call set ".%%code:~%%i,1%%=%%yushu:~%%i,1%%"
- for %%a in (%idbox%) do (
- set id=%%a
- set/p=!id:#=?!<nul
- for /l %%b in (0 1 15) do (
- call set /a "sum+=%%id:~%%b,1%%*%%muli:~%%b,1%%"
- )
- for %%c in (0 1 2 3 4 5 6 7 8 9) do (
- if not defined yes (
- set /a t_sum=sum+%%c*2
- set /a t_mod=t_sum%%11
- set t_mod=!t_mod:10=t!
- for /f "delims==" %%d in ('set .^|findstr /e !t_mod!') do (
- if "%%d"==".!id:~-1!" (
- echo; 应该是:!id:#=%%c!
- set yes=1
- )
- set "t_sum=" & set "t_mod="
- )
- )
- )
- set "sum="
- set "yes="
- )
- echo;over&pause>nul&exit /b
复制代码
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |