マイナンバーのチェックディジットをObjective-Cで計算する



[マイナンバーのチェックデジットを計算する](http://qiita.com/qube81/items/fa6ef94d3c8615b0ce64)の記事を参考に、有志によって様々な言語用にコードが書かれていますが、Objective-Cのコードがなかったので書いてみました。

```objc:NSString+ValidateMyNumber.h
#import <Foundation/Foundation.h>

@interface NSString (ValidateMyNumber)

@property (readonly) BOOL isValidMyNumber;

- (BOOL)isValidMyNumber;
+ (BOOL)isValidMyNumber:(NSString *)myNumber;

@end
```

```objc:NSString+ValidateMyNumber.m
#import "NSString+ValidateMyNumber.h"

@implementation NSString (ValidateMyNumber)

- (BOOL)isValidMyNumber {
    return [NSString isValidMyNumber:self];
}

+ (BOOL)isValidMyNumber:(NSString *)myNumber {
    
    // 12桁であるかのチェック
    if (myNumber.length != 12) {
        return NO;
    }
    
    // 数字のみであるかのチェック
    NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:myNumber];
    if (![[NSCharacterSet decimalDigitCharacterSet] isSupersetOfSet:characterSet]) {
        return NO;
    }
    
    // チェックディジット取得
    NSInteger checkDigit = [myNumber substringFromIndex:11].integerValue;
    
    // チェックディジットを除く数字を1文字ずつ配列に入れる
    NSMutableArray<NSString *> *digits = [NSMutableArray arrayWithCapacity:11];
    [myNumber enumerateSubstringsInRange:NSMakeRange(0, 11)
                                 options:NSStringEnumerationByComposedCharacterSequences | NSStringEnumerationReverse
                              usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
                                  [digits addObject:substring];
                              }];
    
    // 数列の和を11で割った余りを計算
    NSInteger sum = 0;
    NSInteger n = 1;
    for (NSString *digit in digits) {
        NSInteger p = digit.integerValue;
        NSInteger q = n <= 6 ? n + 1 : n - 5;
        sum += p * q;
        n++;
    }
    
    NSInteger remainder = sum % 11;
    return remainder <= 1 ? checkDigit == 0 : checkDigit == (11 - remainder);
}

@end
```

## 使い方

NSStringのカテゴリにしてあります。

```objc:使い方サンプル1
NSString *myNumber = @"123456789018";
BOOL valid = myNumber.isValidMyNumber; // or [myNumber isValidMyNumber];
```

```objc:使い方サンプル2
BOOL valid = [NSString isValidMyNumber:@"123456789018"];
```

## テストコード

```objc:ValidateMyNumberTests.m
#import <XCTest/XCTest.h>
#import "NSString+ValidateMyNumber.h"

@interface ValidateMyNumberTests : XCTestCase

@end

@implementation ValidateMyNumberTests

- (void)setUp {
    [super setUp];
    // Put setup code here. This method is called before the invocation of each test method in the class.
}

- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
    [super tearDown];
}

- (void)testMyNumber {
    XCTAssertFalse(@"123456789010".isValidMyNumber);
    XCTAssertFalse(@"123456789011".isValidMyNumber);
    XCTAssertFalse(@"123456789012".isValidMyNumber);
    XCTAssertFalse(@"123456789013".isValidMyNumber);
    XCTAssertFalse(@"123456789014".isValidMyNumber);
    XCTAssertFalse(@"123456789015".isValidMyNumber);
    XCTAssertFalse(@"123456789016".isValidMyNumber);
    XCTAssertFalse(@"123456789017".isValidMyNumber);
    XCTAssertTrue(@"123456789018".isValidMyNumber); // true
    XCTAssertFalse(@"123456789019".isValidMyNumber);
    XCTAssertTrue(@"023456789013".isValidMyNumber); // true
}

@end
```

マイナンバーのチェックデジットの詳細については[元ネタ](http://qiita.com/qube81/items/fa6ef94d3c8615b0ce64)をどうぞ。