LoginSignup
4
4

More than 5 years have passed since last update.

D 言語でコンパイル時にマイナンバーの妥当性をチェックするテンプレート

Last updated at Posted at 2015-12-08

発端

やってみよう。

実装

どやさ。

mynumber.d
import std.algorithm.iteration : map;
import std.functional : unaryFun;
import std.numeric : dotProduct;
import std.range : dropOne, iota, repeat, zip;
enum isValidMyNumber(ulong x) =
    x < 10UL^^12 &&
    x.repeat
    .zip(0.iota(12).map!"10UL^^a")
    .map!"a[0]/a[1]%10"
    .unaryFun!(n12r => n12r.front ==
        n12r.dropOne
        .dotProduct(1.iota(12).map!"a<7?a+1:a-5")
        .unaryFun!"a%11"
        .unaryFun!"a<2?0:11-a");


// ulong
static assert(!  isValidMyNumber! 123456789010);
static assert(!  isValidMyNumber! 123456789011);
static assert(!  isValidMyNumber! 123456789012);
static assert(!  isValidMyNumber! 123456789013);
static assert(!  isValidMyNumber! 123456789014);
static assert(!  isValidMyNumber! 123456789015);
static assert(!  isValidMyNumber! 123456789016);
static assert(!  isValidMyNumber! 123456789017);
static assert(   isValidMyNumber! 123456789018);
static assert(!  isValidMyNumber! 123456789019);
static assert(   isValidMyNumber!  23456789013);
static assert(!  isValidMyNumber!9123456789010);

UFCS チェインのために std.functional.unaryFun を挟んでいますが、ナイーブにラムダ記法を使って (a => expr)(value) と即時呼び出しすると括弧が多くなるし、流れが前後するので読みにくくなるわけです。

えぇ、引数に文字列や文字からなる input range なんかを渡したいという需要もありますよね。

mynumber.d
import std.range.primitives : ElementType, isInputRange;
import std.traits : isSomeChar, isSomeString;
template isValidMyNumber(alias x)
    if (isSomeString!(typeof(x)) ||
        isInputRange!(typeof(x)) &&
        isSomeChar!(ElementType!(typeof(x))))  // てきとー
{
    import std.algorithm.searching : all;
    import std.ascii : isDigit;
    import std.range : walkLength;
    static if (x.walkLength == 12 && x.all!isDigit)
    {
        import std.conv : to;
        alias isValidMyNumber = isValidMyNumber!(to!ulong(to!dstring(x)));
    }
    else
    {
        enum isValidMyNumber = false;
    }
}


// string
static assert(!  isValidMyNumber! "123456789010");
static assert(!  isValidMyNumber! "123456789011");
static assert(!  isValidMyNumber! "123456789012");
static assert(!  isValidMyNumber! "123456789013");
static assert(!  isValidMyNumber! "123456789014");
static assert(!  isValidMyNumber! "123456789015");
static assert(!  isValidMyNumber! "123456789016");
static assert(!  isValidMyNumber! "123456789017");
static assert(   isValidMyNumber! "123456789018");
static assert(!  isValidMyNumber! "123456789019");
static assert(   isValidMyNumber! "023456789013");
static assert(!  isValidMyNumber!  "23456789013");
static assert(!  isValidMyNumber!"9123456789010");
static assert(!  isValidMyNumber! "o23AS67890I3");

// InputRange
import std.range : chain;
static assert(!  isValidMyNumber!( "123456789010".chain("")));
static assert(!  isValidMyNumber!( "123456789011".chain("")));
static assert(!  isValidMyNumber!( "123456789012".chain("")));
static assert(!  isValidMyNumber!( "123456789013".chain("")));
static assert(!  isValidMyNumber!( "123456789014".chain("")));
static assert(!  isValidMyNumber!( "123456789015".chain("")));
static assert(!  isValidMyNumber!( "123456789016".chain("")));
static assert(!  isValidMyNumber!( "123456789017".chain("")));
static assert(   isValidMyNumber!( "123456789018".chain("")));
static assert(!  isValidMyNumber!( "123456789019".chain("")));
static assert(   isValidMyNumber!( "023456789013".chain("")));
static assert(!  isValidMyNumber!(  "23456789013".chain("")));
static assert(!  isValidMyNumber!("9123456789010".chain("")));
static assert(!  isValidMyNumber!( "o23AS67890I3".chain("")));
static assert(!  isValidMyNumber!( "l23AS67890I3".chain("")));

文字列やそれっぽいのを ulong に変換して最初の実装に丸投げするだけのやっつけテンプレートです。static assert 部で文字列から input range(非文字列扱い)をでっち上げるために std.range.chain を使ったのは秘密です。

感想

D 言語のマルチパラダイム性をアピールするチャンスだと思いました。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4