Help us understand the problem. What is going on with this article?

Perl5,Perl6でマイナンバーのチェックデジットを計算する

More than 3 years have passed since last update.

あわせて読みたい

言語 リンク
Ruby マイナンバーのチェックデジットを計算する
C++ C++でマイナンバーのチェックデジットを計算する
Python Python マイナンバー検証用モジュールを公開
PHP マイナンバーのチェックデジットを計算する PHP版
C# C#でマイナンバーのチェックデジットを計算する
SQL マイナンバーのチェックデジットを計算する(SQLで)
PowerShell WindowsPowerShell & C#マイナンバーのチェックデジットを計算する
JavaScript, Groovy JavaScriptとGroovyでマイナンバーのチェックデジットを計算する
Haskell Haskellでマイナンバーのチェックデジットを計算する
Haskell マイナンバー数字列の確認
Java マイナンバーのチェックデジットを計算する(Java編)
C, Go, Bash, Excel etc... マイナンバーのチェックデジットの検算をざっくり1割くらい高速化する(計ってないので知らんけど)
Go マイナンバーのチェックデジットをGoで計算する
Swift マイナンバーのチェックデジットをSwiftで計算する
Vim script Vim からマイナンバーを検証出来るプラグイン書いた。
Gauche Scheme(Gauche)でマイナンバーのチェックデジットを計算する
OCaml OCaml でマイナンバーのチェックデジットを計算する
Rust My Number validator for Rust

説明

流行に乗ってマイナンバーのチェックデジットを計算してみます。
Ruby 版を真似て書いています。

Perl5

mynumber_validate.pl
#!/usr/bin env perl

use v5.18;
use List::Util 'sum';
use feature qw(say switch);
no warnings 'experimental';

&main;exit;

sub main{
  say validate_my_number('123456789010'); #=> false
  say validate_my_number('123456789011'); #=> false
  say validate_my_number('123456789012'); #=> false
  say validate_my_number('123456789013'); #=> false
  say validate_my_number('123456789014'); #=> false
  say validate_my_number('123456789015'); #=> false
  say validate_my_number('123456789016'); #=> false
  say validate_my_number('123456789017'); #=> false
  say validate_my_number('123456789018'); #=> true
  say validate_my_number('123456789019'); #=> false
  say validate_my_number('023456789013'); #=> true (先頭が0の場合)
}

sub validate_my_number{
  # 整数列化
  my @digits = split'', $_[0];

  # 12桁しか認めない
  return 'false' unless @digits == 12;

  # チェックデジットを分離します
  my $check_digit = pop @digits;

  # P(n) 定義
  my $P = sub {
      my @digits = @_;
      return sub {
        my $n = $_[0];
        return $digits[ -$n ];
      };
  }->(@digits);

  # Q(n) 定義
  my $Q = sub {
        my $n = $_[0];
        return ($n<= 6) ? $n+1 : $n-5;
  };

  # 数列の和を11で割った余りを計算します
  my $remainder = ( sum map{ $P->($_) * $Q->($_) } 1..11 ) % 11;

  given( $remainder ){
    when ([0,1]){
      return $check_digit == 0 ? 'true' : 'false';
    }
    default{
      return $check_digit == 11 - $remainder ? 'true' : 'false';
    }
  }
}

Perl6

perl6_mynumber_validate.pl
use v6;

sub MAIN (){
  say validate_my_number('123456789010'); #=> false
  say validate_my_number('123456789011'); #=> false
  say validate_my_number('123456789012'); #=> false
  say validate_my_number('123456789013'); #=> false
  say validate_my_number('123456789014'); #=> false
  say validate_my_number('123456789015'); #=> false
  say validate_my_number('123456789016'); #=> false
  say validate_my_number('123456789017'); #=> false
  say validate_my_number('123456789018'); #=> true
  say validate_my_number('123456789019'); #=> false
  say validate_my_number('023456789013'); #=> true (先頭が0の場合)
}

sub validate_my_number( Str $mynumber ){
  # 整数列化
  my @digits = $mynumber.comb;

  # 12桁しか認めない
  return False unless @digits.elems == 12;

  # チェックデジットを分離します
  my $check_digit = @digits.pop;

  # P(n) 定義
  my $P = sub ( @digits ) {
      return sub ( Int $n ) {
        return @digits[ *-$n ];
      };
  }.(@digits);

  # Q(n) 定義
  my $Q = sub ( Int $n ) {
    return ($n <= 6) ?? $n + 1 !! $n - 5;
  };

  # 数列の和を11で割った余りを計算します
  my $remainder = ( [+] (1..11).map:{ $P.(+$_) * $Q.(+$_) } ) % 11;

  given $remainder {
    when 0|1 {
      return $check_digit == 0;
    }
    default {
      return $check_digit == (11 - $remainder);
    }
  }
}

おわりです。

参考や注釈

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away