ðŸŽ‰ Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io ðŸŽ‰

# KiligWY's solution

## to Luhn in the Objective-C Track

Published at Jul 13 2018 · 0 comments
Instructions
Test suite
Solution

Given a number determine whether or not it is valid per the Luhn formula.

The Luhn algorithm is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers and Canadian Social Insurance Numbers.

The task is to check if a given string is valid.

## Validating a Number

Strings of length 1 or less are not valid. Spaces are allowed in the input, but they should be stripped before checking. All other non-digit characters are disallowed.

## Example 1: valid credit card number

4539 1488 0343 6467

The first step of the Luhn algorithm is to double every second digit, starting from the right. We will be doubling

4_3_ 1_8_ 0_4_ 6_6_

If doubling the number results in a number greater than 9 then subtract 9 from the product. The results of our doubling:

8569 2478 0383 3437

Then sum all of the digits:

8+5+6+9+2+4+7+8+0+3+8+3+3+4+3+7 = 80

If the sum is evenly divisible by 10, then the number is valid. This number is valid!

## Example 2: invalid credit card number

8273 1232 7352 0569

Double the second digits, starting from the right

7253 2262 5312 0539

Sum the digits

7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57

57 is not evenly divisible by 10, so this number is not valid.

## Setup

There are two different methods of getting set up to run the tests with Objective-C:

• Create an Xcode project with a test target which will run the tests.
• Use the ruby gem objc as a test runner utility.

Both are described in more detail here: http://exercism.io/languages/objective-c

### Submitting Exercises

When submitting an exercise, make sure your solution file is in the same directory as the test code.

The submit command will look something like:

exercism submit <path-to-exercism-workspace>/objective-c/luhn/Luhn.m

You can find the Exercism workspace by running exercism debug and looking for the line beginning with Workspace.

## Source

The Luhn Algorithm on Wikipedia http://en.wikipedia.org/wiki/Luhn_algorithm

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### LuhnTest.m

#import <XCTest/XCTest.h>

#if __has_include("LuhnExample.h")
# import "LuhnExample.h"
# else
# import "Luhn.h"
#endif

@interface LuhnTest : XCTestCase

@end

@implementation LuhnTest

- (void)testSingleDigitStringNotValid {
Luhn *luhn = [[Luhn alloc] initWithString:@"1"];
XCTAssertFalse(luhn.isValid);
}

- (void)testSingleZeroInvalid {
Luhn *luhn = [[Luhn alloc] initWithString:@"0"];
XCTAssertFalse(luhn.isValid);
}

- (void)testSimpleValidSINRemainsValidIfReversed {
Luhn *luhn = [[Luhn alloc] initWithString:@"059"];
XCTAssertTrue(luhn.isValid);
}

- (void)testSimpleValidSINInvalidIfReversed {
Luhn *luhn = [[Luhn alloc] initWithString:@"59"];
XCTAssertTrue(luhn.isValid);
}

Luhn *luhn = [[Luhn alloc] initWithString:@"055 444 285"];
XCTAssertTrue(luhn.isValid);
}

Luhn *luhn = [[Luhn alloc] initWithString:@"055 444 286"];
XCTAssertFalse(luhn.isValid);
}

- (void)testInvalidCreditCard {
Luhn *luhn = [[Luhn alloc] initWithString:@"8273 1232 7352 0569"];
XCTAssertFalse(luhn.isValid);
}

- (void)testValidStringsWithANonDigitInvalid {
Luhn *luhn = [[Luhn alloc] initWithString:@"055a 444 285"];
XCTAssertFalse(luhn.isValid);
}

- (void)testValidStringsWithPunctuationInvalid {
Luhn *luhn = [[Luhn alloc] initWithString:@"055-444-285"];
XCTAssertFalse(luhn.isValid);
}

- (void)testValidStringWithSymbolsInvalid {
Luhn *luhn = [[Luhn alloc] initWithString:@"055Â£ 444\$ 285"];
XCTAssertFalse(luhn.isValid);
}

- (void)testSingleZeroWithSpaceInvalid {
Luhn *luhn = [[Luhn alloc] initWithString:@" 0"];
XCTAssertFalse(luhn.isValid);
}

- (void)testMoreThanOneZeroValid {
Luhn *luhn = [[Luhn alloc] initWithString:@"0000 0"];
XCTAssertTrue(luhn.isValid);
}

- (void)testInputDigit9CorrectConverted {
Luhn *luhn = [[Luhn alloc] initWithString:@"091"];
XCTAssertTrue(luhn.isValid);
}

@end

### Luhn.h

#import <Foundation/Foundation.h>

@interface Luhn : NSObject

@property (nonatomic, assign) BOOL isValid;

- (instancetype)initWithString:(NSString *)input;

@end

### Luhn.m

#import "Luhn.h"

@implementation Luhn

- (instancetype)initWithString:(NSString *)input {
if (self = [super init]) {
if ([[NSPredicate predicateWithFormat:@"SELF MATCHES %@", @"^[0-9 ]{1,}\$"] evaluateWithObject:input]) {
input = [input stringByReplacingOccurrencesOfString:@" " withString:@""];
if (input.length <= 1) {
self.isValid = false;
} else {
__block NSInteger sum = 0;
[input enumerateSubstringsInRange:NSMakeRange(0, input.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
if ((input.length % 2 == 0 && substringRange.location % 2 == 0)
|| (input.length % 2 == 1 && substringRange.location % 2 == 1)) {
if ([substring integerValue] * 2 > 9) {
sum += ([substring integerValue] * 2 - 9);
} else {
sum += ([substring integerValue] * 2);
}
} else {
sum += [substring integerValue];
}
}];
self.isValid = sum % 10 == 0 ? YES : NO;
}
} else {
self.isValid = NO;
}
}
return self;
}

@end