Search code examples
iosobjective-cbarcodechecksum

How to identify whether a number is a UPC code or just simple number ? is there any particular format to identify a UPC code?


Is there any format we can use to identify UPC code instead of checking only for number of digits ?


Solution

  • I have some Objective-C code that validates a user entered string to see if it is a valid UPC or EAN barcode. This supports UPC, ISBN, and EAN (8, 13, and 14).

    If you have a number, convert it to a string first to use this method. This method assumes that the barcode string only has digits 0-9 or an X (some ISBN barcodes can have an X).

    - (BOOL)validBarcode:(NSString *)code {
        int len = [code length];
        switch (len) {
            case 8: // EAN-8
            {
                int check = [code intForDigitAt:7];
                int val = (10 - 
                           (([code intForDigitAt:1] + [code intForDigitAt:3] + [code intForDigitAt:5] +
                             ([code intForDigitAt:0] + [code intForDigitAt:2] + [code intForDigitAt:4] + [code intForDigitAt:6]) *
                             3) % 10)) % 10;
    
                return check == val;
            }
            case 10: // ISBN
            {
                int check = [code intForDigitAt:9];
                int sum = 0;
                for (int i = 0; i < 9; i++) {
                    sum += [code intForDigitAt:i] * (i + 1);
                }
                int val = sum % 11;
    
                if (val == 10) {
                    return [code characterAtIndex:9] == 'X' || [code characterAtIndex:9] == 'x';
                } else {
                    return check == val;
                }
            }
            case 12: // UPC
            {
                int check = [code intForDigitAt:11];
                int val = (10 - 
                           (([code intForDigitAt:1] + [code intForDigitAt:3] + [code intForDigitAt:5] + [code intForDigitAt:7] + [code intForDigitAt:9] + 
                             ([code intForDigitAt:0] + [code intForDigitAt:2] + [code intForDigitAt:4] + [code intForDigitAt:6] + [code intForDigitAt:8] + [code intForDigitAt:10]) *
                             3) % 10)) % 10;
    
                return check == val;
            }
            case 13: // EAN-13
            {
                int check = [code intForDigitAt:12];
                int val = (10 - 
                           (([code intForDigitAt:0] + [code intForDigitAt:2] + [code intForDigitAt:4] + [code intForDigitAt:6] + [code intForDigitAt:8] + [code intForDigitAt:10] + 
                             ([code intForDigitAt:1] + [code intForDigitAt:3] + [code intForDigitAt:5] + [code intForDigitAt:7] + [code intForDigitAt:9] + [code intForDigitAt:11]) *
                             3) % 10)) % 10;
    
                return check == val;
            }
            case 14: // EAN-14
            {
                int check = [code intForDigitAt:13];
                int val = (10 - 
                           (([code intForDigitAt:1] + [code intForDigitAt:3] + [code intForDigitAt:5] + [code intForDigitAt:7] + [code intForDigitAt:9] + [code intForDigitAt:11] + 
                             ([code intForDigitAt:0] + [code intForDigitAt:2] + [code intForDigitAt:4] + [code intForDigitAt:6] + [code intForDigitAt:8] + [code intForDigitAt:10] + [code intForDigitAt:12]) *
                             3) % 10)) % 10;
    
                return check == val;
            }
            default:
                return NO;
        }
    }
    

    This makes use of a category method I added to NSString:

    - (int)intForDigitAt:(NSUInteger)index {
        unichar ch = [self characterAtIndex:index];
        if (ch >= '0' && ch <= '9') {
            return ch - '0';
        } else
            return 0;
    }