Skip to content

Instantly share code, notes, and snippets.

@maxchuquimia
Created October 23, 2015 08:51
Show Gist options
  • Save maxchuquimia/806f7bd5edbabd6227bb to your computer and use it in GitHub Desktop.
Save maxchuquimia/806f7bd5edbabd6227bb to your computer and use it in GitHub Desktop.
Swiftly calculates a check-digit for GTIN-8, GTIN-12, GTIN-13, GTIN-14 and SSCC codes.
import Foundation
@objc class GTINCalculator: NSObject {
/*!
An exception thrown when there is a calculation error
- BadDigit: a substring of the input string could not be read as an `Int`
*/
enum GTINCalculatingError: ErrorType {
case BadDigit(stringValue: String)
}
/*!
Calculate a check digit for a GTIN string
- parameter gtin: the original number - a string of 7, 11, 12 or 13 digits for GTIN-8, GTIN-12, GTIN-13 and GTIN-14 respectively. Will also work for SSCC (17 digits)
- throws: GTINCalculatingError
- returns: a string with one more character than `$0`
*/
class func calculateCheckDigitForGTIN(gtin: String) throws -> String {
let mod = gtin.characters.count % 2 == 0
let a = mod ? 1 : 3
let b = mod ? 3 : 1
do {
let calculated = try gtin.characters.map {String($0)}
.map(verifyInt)
.map {Int($0)!}
.enumerate()
.map {($0 % 2 == 0 ? a : b) * $1}
.reduce(0, combine:+)
let checkDigit = Int(ceil(Double(calculated) / 10.0) * 10)
return "\(gtin)\(checkDigit - calculated)"
}
catch let e as GTINCalculatingError {
throw e
}
}
/*!
Verifies that a string can be converted to an `Int`
- parameter c: the string to check
- throws: GTINCalculatingError
- returns: the input string `c`
*/
private class func verifyInt(c: String) throws -> String {
guard let _ = Int(c) else {
throw GTINCalculatingError.BadDigit(stringValue: c)
}
return c
}
class func test() {
//SSCC
assert(try! calculateCheckDigitForGTIN("14253165132135354") == "142531651321353546")
//GTIN-14
assert(try! calculateCheckDigitForGTIN("1456541542542") == "14565415425426")
//GTIN-13
assert(try! calculateCheckDigitForGTIN("629104150021") == "6291041500213")
//GTIN-12
assert(try! calculateCheckDigitForGTIN("48564186514") == "485641865148")
//GTIN-8
assert(try! calculateCheckDigitForGTIN("9638507") == "96385074")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment