ISBN check digit generator

Share

现在国际上通用的check digit的算法有很多种,例如:UPC、ISBN、 CUSIP。。。等等。。

这里重点解释下ISBN


The final character of a ten digit International Standard Book Number is a check digit computed so that multiplying each digit by its position in the number (counting from the right) and taking the sum of these products modulo 11 is 0. The last digit (which is multiplied by 1) is the check digit, chosen to make the sum correct. It may need to have the value 10, which is represented as the letter X. For example, take the ISBN 0-201-53082-1. The sum of products is 0×10 + 2×9 + 0×8 + 1×7 + 5×6 + 3×5 + 0×4 + 8×3 + 2×2 = 98 modulo 11 (10) subtracted from 11 ≡ 1. So the ISBN is valid.

While this may seem more complicated than the first scheme, it can be validated very simply by adding all the products together then dividing by 11. If the result is an integer then the ISBN is valid.

ISBN 13 (in use January, 2007) is equal to the EAN-13 code found underneath a book’s barcode. Its check digit is generated the same way as the UPC, except the even digits are multiplied by 3 instead of the odd digits (a UPC can be converted to EAN-13 by prefixing a 0).

下面是这次开发中写的,需要用到的规则:

/**
 * @(#)CheckDigit.java  1.0.2.8.1 04/30/08
 * 
 * Copyright 2008 LeeMENZ, Inc. All rights reserved.
 * 
 */
package jp.co.kistem.permission.common.utils;

/**
 * 
 * The <code>CheckDigit</code> class used to check Digit string.
 * in the package of jp.co.kistem.permission.common.utils * <p>
 * You can use it like this:
 * <blockquote><pre>
 *     CheckDigit.ConvertToISBN(int source, int leng, int mod, int heav,int comp);
 * </pre></blockquote><p>
 * For example:
 * <blockquote><pre>
 *     String isbn = CheckDigit.ConvertToISBN(12345678,9,10,2,10);
 * </pre></blockquote><p>
 * and the isbn will be:123456782
 * 
 * @author    Kooqi.LEE
 * @company   leemenz (C) copyright
 * @time      April 1, 2008  10:24:06 AM
 * @version   1.0.2.8.1  <url>http://www.icnote.com/</url>
 * @package  com.icnote.permission.common.utils
 * 
 * @see com.icnote.permission.common.utils.CheckDigit
 * 
 */
public class CheckDigit {
    
    /**
     *  This method used to excute the arithmetic
     * 
     * @param source    the source integer needs to be arithmetic
     * @param leng      the ISBN&#39;s length
     * @param mod       module data
     * @param heav      heav data
     * @param comp      comp data
     * @return final    string
     * @author lee
     */
    public static String ConvertToISBN(int source, int leng, int mod, int heav,
            int comp) {
        String result = String.valueOf(source);

        int sour[] = reverseInt(source);
        int temp = 0;
        int _resultInt = 0;
        int _res = 0;

        if (mod == 10 && comp == 10) {
            /* M10W2 process start (10 2 10) */
            if (heav == 2) {
                int _tmp = 2;
                for (int i = sour.length - 1; i >= 0; i--) {
                    temp = sour<i> * _tmp;
                    if (_tmp == 2)
                        _tmp = 1;
                    else if (_tmp == 1)
                        _tmp = 2;
                    if (temp / 10 != 0)
                        temp = temp / 10 + temp % 10;
                    _resultInt += temp;
                }
            /* M10W3 process start (10 3 10) */
            } else if (heav == 3) {
                int _tmp = 3;
                for (int i = sour.length - 1; i >= 0; i--) {
                    temp = sour<i> * _tmp;
                    if (_tmp == 3)
                        _tmp = 1;
                    else if (_tmp == 1)
                        _tmp = 3;
                    _resultInt += temp;
                }
            }
            _res = _resultInt % 10;
            if (_res == 0)
                _resultInt = 0;
            else
                _resultInt = 10 - _res;
        /* M11W27 process start (11 2~7 11) */
        } else if (mod == 11 && comp == 11) {
            if (heav == 2) {
                int _tmp = 2;
                for (int i = sour.length - 1; i >= 0; i--) {
                    temp = sour<i> * _tmp;
                    if (_tmp == 7) {
                        _tmp = 2;
                    } else
                        _tmp++;
                    _resultInt += temp;
                }
            /* M11W10 process start (11 1~0 11) */
            } else if (heav == 1) {
                int _tmp = 1;
                for (int i = sour.length - 1; i >= 0; i--) {
                    _resultInt += sour<i> * _tmp;
                    _tmp++;
                }
            }
            _res = _resultInt % 11;
            if (_res == 0 &#124;&#124; _res == 1)
                _resultInt = 0;
            else
                _resultInt = 11 - _res;
        }
        /* Concatenate the check character */
        result = result + String.valueOf(_resultInt);

        /* If the result&#39;s length less than the one given,
         * here will add "0" before the result
         */
        if (result.length() < leng) {
            int _tmpLength = leng - result.length();
            for (int i = 0; i < _tmpLength; i++) {
                result = "0" + result;
            }
        }

        return result;
    }

    /**
     *  This method reverse an integer to an integer array
     *  
     * @param source    Source int needs to be reversed
     * @return int[]    An integer array which contains single integer
     * @author lee
     */
    private static int[] reverseInt(int source) {

        String sourceStr = String.valueOf(source);
        /* Prase the sourceStr to Double formate */
        double sourceDou = Double.parseDouble(sourceStr);
        /* Initial the length of the array */
        int res[] = new int[sourceStr.length()];

        /* Add every single charater to array in integer formate */
        for (int i = 0; i < res.length; i++) {
            double pow = Math.pow(10.0, Double.parseDouble(String
                    .valueOf(res.length - i - 1)));
            String rad_double = String.valueOf(sourceDou / pow);
            res<i> = Integer.parseInt(rad_double.substring(0, rad_double
                    .indexOf(".")));
            sourceDou = sourceDou - pow * res<i>;
        }
        return res;
    }
}


类似的check digit的算法还有:

The tenth digit of the National Provider Identifier for the healthcare industry more

The Australian Tax File Number (based on modulo 11)

The ninth digit of a Canadian Social Insurance Number (SIN)

The North American CUSIP number

The International SEDOL number

The International Securities Identifying Number (ISIN)

The International CAS registry number’s final digit.

Modulo 10 check digits in credit card account numbers, calculated with the Luhn algorithm.

Also used in the Norwegian KID (customer identification number) numbers used in bank giros (credit transfer).

The final character encoded in a magnetic stripe card is a computed Longitudinal redundancy check

final digit of a POSTNET code

final digit of an ISSN code

final digit of a DUNS number (though this is scheduled to change, such as that the final digit will be chosen freely in new allocations, rather than being a check digit)

The Spanish fiscal identification number (número de identificación fiscal, NIF), (based on modulo 23).

The ninth digit of a Vehicle Identification Number (VIN).

The ninth digit of an Israeli Teudat Zehut (Identity Card) number.

The 13th digit of Former Yugoslav Unique Master Citizen Number (JMBG)

Last check digit in EAN/UPC serialisation of Global Trade Identification Number (GTINs). It applies to GTIN-8, GTIN-12, GTIN-13 and GTIN-14.

The seventh character of a New Zealand NHI Number.