マイナンバーのチェックデジットを計算するの記事を参考に、有志によって様々な言語用にコードが書かれていますが、Objective-Cのコードがなかったので書いてみました。
NSString+ValidateMyNumber.h
#import <Foundation/Foundation.h>
@interface NSString (ValidateMyNumber)
@property (readonly) BOOL isValidMyNumber;
- (BOOL)isValidMyNumber;
+ (BOOL)isValidMyNumber:(NSString *)myNumber;
@end
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のカテゴリにしてあります。
使い方サンプル1
NSString *myNumber = @"123456789018";
BOOL valid = myNumber.isValidMyNumber; // or [myNumber isValidMyNumber];
使い方サンプル2
BOOL valid = [NSString isValidMyNumber:@"123456789018"];
テストコード
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
マイナンバーのチェックデジットの詳細については元ネタをどうぞ。