🎉 Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io 🎉 # ingemar's solution

## to Luhn in the Objective-C Track

Published at Jul 24 2019 · 1 comment
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);
}

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

- (void)testInvalidCanadianSIN {
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-tests/Luhn.h

``````//
//  Luhn.h
//  luhn-tests
//
//  Created by Ingemar Pertl on 23.07.19.
//  Copyright © 2019 Ingemar Pertl. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Luhn : NSObject

@property (nonatomic) BOOL isValid;

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

@end

NS_ASSUME_NONNULL_END``````

### luhn-tests/Luhn.m

``````//
//  Luhn.m
//  luhn-tests
//
//  Created by Ingemar Pertl on 23.07.19.
//  Copyright © 2019 Ingemar Pertl. All rights reserved.
//

#import "Luhn.h"

@interface Luhn ()

@property (nonatomic, copy) NSString *numberAsString;

- (void)checkLuhn;

- (NSNumber *)doubleByLuhn:(int)number;

@end

@implementation Luhn

- (instancetype)initWithString:(NSString *)input {
self = [super init];
self.numberAsString = input;

[self checkLuhn];

return self;
}

- (void)checkLuhn {
// remove all spaces
NSString *cleanedInput = [[self.numberAsString componentsSeparatedByCharactersInSet:
[NSCharacterSet whitespaceCharacterSet]] componentsJoinedByString:@""];

if(cleanedInput.length <= 1){
self.isValid = false;
return;
}

NSMutableCharacterSet *characterSet = [NSMutableCharacterSet letterCharacterSet];
[characterSet formUnionWithCharacterSet:[NSMutableCharacterSet punctuationCharacterSet]];
if([cleanedInput rangeOfCharacterFromSet:characterSet].location != NSNotFound) {
self.isValid = false;
return;
}

// double every second digit
for (int i = (int)cleanedInput.length - 2; i >= 0; i -= 2) {
NSNumber *doubled = [self doubleByLuhn:[cleanedInput characterAtIndex:i] - '0'];
cleanedInput = [cleanedInput stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:[NSString stringWithFormat:@"%@",doubled]];
}

// sum all of the digits
int sum = 0;
for(int i = 0; i < (int)cleanedInput.length; i++) {
sum += [cleanedInput characterAtIndex:i] - '0';
}

self.isValid = sum % 10 == 0;
}

- (NSNumber *)doubleByLuhn:(int)number {
int doubled = number * 2;
if(doubled > 9)
doubled -= 9;

return [NSNumber numberWithInt:doubled];
}

@end``````

## Community comments

Find this solution interesting? Ask the author a question to learn more. forget my question in the reflection panel ;-) I took a look at the community solutions and found some nice input! And one zero is invalid because one digit itself is invalid!

### ingemar's Reflection

I've a problem with some test cases:
testSingleZeroWithSpaceInvalid and testMoreThanOneZeroValid

I don't understand why one zero is invalid and multiple are valid? The sum in the end is zero for both, right?