Checksum an ISBN

From CodeCodex

Implementations[edit]

D[edit]

import std.stdio, std.string;

/// Checks if the passed string is a valid ISBN number.
bool isISBN(string isbn) {
    if (isbn.length != 10 ||
        isbn[0 .. 9].countchars("^0-9") ||
        inPattern(isbn[9], "^0-9xX"))
        return false;

    int sum;
    foreach(i, c; isbn[0 .. $-1])
        sum += (10 - i) * (c - '0');

    int checksum = (11 - (sum % 11)) % 11;
    if (isbn[9] == 'X' || isbn[9] == 'x')
        return checksum == 10;
    else
        return checksum == (isbn[9] - '0');
}

unittest {
    string ok = "031234161X 0525949488 076360013X 0671027360 0803612079
                 0307263118 0684856093 0767916565 0071392319 1400032806 0765305240";
    foreach(code; ok.split())
        assert(isISBN(code));

    string bad = "0312341613 052594948X 0763600138 0671027364 080361207X 0307263110
                  0684856092 0767916567 0071392318 1400032801 0765305241 031234161
                  076530Y241 068485609Y";
    foreach(code; bad.split())
        assert(!isISBN(code));
    writefln("Unittest of isISBN() passed.");
}

Erlang[edit]

is_ISBN10(Isbn) when length(Isbn) =/= 10 -> false;
is_ISBN10(Isbn) ->
    ISBN = string:to_upper(Isbn),
    case re:run(ISBN, "[0-9]{9}[0-9X]") of
        {match, _} ->
            F = fun(C, {I, Acc}) -> {I - 1, Acc + I * (C - $0)} end,
            {_, Sum} = lists:foldl(F, {10, 0}, lists:sublist(ISBN, 9)),
            Check = (11 - Sum rem 11) rem 11,
            lists:last(ISBN) =:= lists:nth(Check+1, "0123456789X");
        _ -> false
    end.

test_ISBN() ->
    F = fun(X) -> io:format("~p ~p~n", [X, is_ISBN10(X)]) end,
    Ok  = "031234161X 0525949488 076360013X 0671027360 0803612079 
           0307263118 0684856093 0767916565 0071392319 1400032806 0765305240",
    lists:foreach(F, string:tokens(Ok, " \r\n")),
    Bad = "0312341613 052594948X 0763600138 0671027364 080361207X 0307263110
           0684856092 0767916567 0071392318 1400032801 0765305241 031234161 
           076530Y241 068485609Y",
    lists:foreach(F, string:tokens(Bad, " \r\n")).

Java[edit]

/**
 * An ISBN Utility
 * @author Julius Schorzman
 * (C) 2006 -- Provided under GPL
 */
public class ISBNUtil {
	/**
	 * Checks if the passed string is a valid ISBN number.
	 * @param isbn The ISBN String
	 * @return true if it is a valid isbn; false in all other cases.
	 */
	public static boolean isISBN(String isbn) {
		
		try {
			if (isbn.length() != 10) {
				return false;
			}
			
			int weight = 10;
			int rollingSum = 0;
			for ( int i = 0 ; i < 9 ; i++ ) {
				int isbnDigit = Character.digit(isbn.charAt(i), 10);
				rollingSum += isbnDigit * weight--;
			}
			
			int mod = rollingSum % 11;
			mod = 11 - mod;
			if ( mod == 11 ) mod = 0;
			
			char checkSum = isbn.charAt(9);
			if (Character.toLowerCase(checkSum) == 'x') {
				if ( mod == 10 ) return true;
			} else {
				if (Character.digit(checkSum, 10) == mod) return true;
			}
			return false;
		} catch (Exception e) {
			return false;
		}
	}
	
	public static void main(String[] args) {
		System.out.println("true: "+ISBNUtil.isISBN("031234161X"));
		System.out.println("true: "+ISBNUtil.isISBN("0525949488"));
		System.out.println("true: "+ISBNUtil.isISBN("076360013X"));
		System.out.println("true: "+ISBNUtil.isISBN("0671027360"));
		System.out.println("true: "+ISBNUtil.isISBN("0803612079"));
		System.out.println("true: "+ISBNUtil.isISBN("0307263118"));
		System.out.println("true: "+ISBNUtil.isISBN("0684856093"));
		System.out.println("true: "+ISBNUtil.isISBN("0767916565"));
		System.out.println("true: "+ISBNUtil.isISBN("0071392319"));
		System.out.println("true: "+ISBNUtil.isISBN("1400032806"));
		System.out.println("true: "+ISBNUtil.isISBN("0765305240"));

		System.out.println("false: "+ISBNUtil.isISBN("0312341613"));
		System.out.println("false: "+ISBNUtil.isISBN("052594948X"));
		System.out.println("false: "+ISBNUtil.isISBN("0763600138"));
		System.out.println("false: "+ISBNUtil.isISBN("0671027364"));
		System.out.println("false: "+ISBNUtil.isISBN("080361207X"));
		System.out.println("false: "+ISBNUtil.isISBN("0307263110"));
		System.out.println("false: "+ISBNUtil.isISBN("0684856092"));
		System.out.println("false: "+ISBNUtil.isISBN("0767916567"));
		System.out.println("false: "+ISBNUtil.isISBN("0071392318"));
		System.out.println("false: "+ISBNUtil.isISBN("1400032801"));
		System.out.println("false: "+ISBNUtil.isISBN("0765305241"));
	}
}

Python[edit]

def isISBN(isbn):
    """Checks if the passed string is a valid ISBN number."""
    if len(isbn) != 10 or not isbn[:9].isdigit():
        return False
    if not (isbn[9].isdigit() or isbn[9].lower() == "x"):
        return False

    tot = sum((10 - i) * int(c) for i, c in enumerate(isbn[:-1]))

    checksum = (11 - tot % 11) % 11
    if isbn[9] == 'X' or isbn[9] == 'x':
        return checksum == 10
    else:
        return checksum == int(isbn[9])

ok = """031234161X 0525949488 076360013X 0671027360 0803612079
        0307263118 0684856093 0767916565 0071392319 1400032806 0765305240"""
for code in ok.split():
    assert isISBN(code)

bad = """0312341613 052594948X 0763600138 0671027364 080361207X 0307263110
         0684856092 0767916567 0071392318 1400032801 0765305241 031234161
         076530Y241 068485609Y"""
for code in bad.split():
    assert not isISBN(code)

print "Tests of isISBN()passed."

Ruby[edit]

def check_ISBN10?(isbn)
  return false  if isbn.size != 10 or isbn !~ /\d{9}(\d|X)/
  sum = isbn[0..-2].split("").each_with_index.map{|c,i|(10-i)*c.to_i}.inject(:+)
  check_digit = (11 - sum % 11) % 11
  isbn[-1] == "0123456789X"[check_digit]
end

ok = %w(031234161X 0525949488 076360013X 0671027360 0803612079
        0307263118 0684856093 0767916565 0071392319 1400032806 0765305240)
ok.each do |isbn|
  puts "#{isbn} is #{check_ISBN10?(isbn)}"
end
puts
bad = %w(0312341613 052594948X 0763600138 0671027364 080361207X 0307263110
         0684856092 0767916567 0071392318 1400032801 0765305241 031234161
         076530Y241 068485609Y)
bad.each do |isbn|
  puts "#{isbn} is #{check_ISBN10?(isbn)}"
end