module StdNum::ISBN

Validate, convert, and normalize ISBNs (10-digit or 13-digit)

Constants

TEN_TO_THIRTEEN_PREFIX
VALID_THIRTEEN_PREFIX

Public Class Methods

allNormalizedValues(isbn) click to toggle source

Return an array of the ISBN13 and ISBN10 (in that order) for the passed in value. You'll only get one value back if it's a 13-digit ISBN that can't be converted to an ISBN10. @param [String] isbn The original ISBN, in 10-character or 13-digit format @return [Array<String,String>, nil] Either the (one or two) normalized ISBNs, or nil if it can't be recognized.

@example Get the normalized values and index them (if valid) or original value (if not)

norms = StdNum::ISBN.allNormalizedValues(rawisbn)
doc['isbn'] = norms ? norms : [rawisbn]
# File lib/library_stdnums.rb, line 180
def self.allNormalizedValues isbn
  isbn = reduce_to_basics isbn, [10,13]
  return [] unless isbn
  case isbn.size
  when 10
    return [self.convert_to_13(isbn), isbn]
  when 13
    return [isbn, self.convert_to_10(isbn)].compact
  end
end
at_least_trying?(isbn) click to toggle source

Does it even look like an ISBN?

# File lib/library_stdnums.rb, line 71
def self.at_least_trying? isbn
  reduce_to_basics(isbn, [10,13]) ? true : false
end
checkdigit(isbn, preprocessed = false) click to toggle source

Compute check digits for 10 or 13-digit ISBNs. See algorithm at en.wikipedia.org/wiki/International_Standard_Book_Number @param [String] isbn The ISBN (we'll try to clean it up if possible) @param [Boolean] preprocessed Set to true if the ISBN has already been through reduce_to_basics @return [String,nil] the one-character checkdigit, or nil if it's not an ISBN string

# File lib/library_stdnums.rb, line 81
def self.checkdigit isbn, preprocessed = false
  isbn = reduce_to_basics isbn, [10,13] unless preprocessed
  return nil unless isbn

  checkdigit = 0
  if isbn.size == 10
    digits = isbn[0..8].split(//).map {|i| i.to_i}
    (1..9).each do |i|
      checkdigit += digits[i-1] * i
    end
    checkdigit = checkdigit % 11
    return 'X' if checkdigit == 10
    return checkdigit.to_s
  else # size == 13
    checkdigit = 0
    digits = isbn[0..11].split(//).map {|i| i.to_i}
    6.times do
      checkdigit += digits.shift
      checkdigit += digits.shift * 3
    end
    check = 10 - (checkdigit % 10)
    check = 0 if check == 10
    return check.to_s
  end
end
convert_to_10(isbn) click to toggle source

Convert to 10 if it's 13 digits and the first three digits are 978. Pass through anything 10-digits, and return nil for everything else. @param [String] isbn The ISBN (we'll try to clean it up if possible) @return [String] The converted 10-character ISBN, nil if something looks wrong, or whatever was passed in if it already looked like a 10-digit ISBN

# File lib/library_stdnums.rb, line 157
def self.convert_to_10 isbn
  isbn = reduce_to_basics isbn, [10,13]

  # Already 10 digits? Just return
  return isbn if isbn.size == 10

  # Can't be converted to ISBN-10? Bail
  return nil unless isbn[0..2] == TEN_TO_THIRTEEN_PREFIX

  prefix = isbn[3..11]
  return prefix + self.checkdigit(prefix + '0')
end
convert_to_13(isbn) click to toggle source

To convert to an ISBN13, throw a '978' on the front and compute the checkdigit We leave 13-digit numbers alone, figuring they're already ok. NO CHECKSUM CHECK IS DONE FOR 13-DIGIT ISBNS! and return nil on anything that's not the right length @param [String] isbn The ISBN (we'll try to clean it up if possible) @return [String, nil] The converted 13-character ISBN, nil if something looks wrong, or whatever was passed in if it already looked like a 13-digit ISBN

# File lib/library_stdnums.rb, line 143
def self.convert_to_13 isbn
  isbn = reduce_to_basics isbn, [10,13]
  return nil unless isbn
  return nil unless valid?(isbn, true)
  return isbn if isbn.size == 13
  prefix = TEN_TO_THIRTEEN_PREFIX + isbn[0..8]
  return prefix + self.checkdigit(prefix + '0', true)
end
normalize(rawisbn) click to toggle source

For an ISBN, normalizing it is the same as converting to ISBN 13 and making sure it's valid

@param [String] rawisbn The ISBN to normalize @return [String, nil] the normalized (to 13 digit) ISBN, or nil on failure

# File lib/library_stdnums.rb, line 128
def self.normalize rawisbn
  isbn = convert_to_13 rawisbn
  if isbn
    return isbn
  else
    return nil
  end
end
valid?(isbn, preprocessed = false) click to toggle source

Check to see if the checkdigit is correct @param [String] isbn The ISBN (we'll try to clean it up if possible) @param [Boolean] preprocessed Set to true if the ISBN has already been through reduce_to_basics @return [Boolean] Whether or not the checkdigit is correct. Sneakily, return 'nil' for

values that don't even look like ISBNs, and 'false' for those that look possible but
don't normalize / have bad checkdigits
# File lib/library_stdnums.rb, line 113
def self.valid? isbn, preprocessed = false
  return nil if isbn.nil?
  isbn = reduce_to_basics(isbn, [10,13]) unless preprocessed
  return nil unless isbn
  return false unless isbn[-1..-1] == self.checkdigit(isbn, true)
  return false unless isbn.size == 10 || valid_isbn13_prefix?(isbn)
  return true
end
valid_isbn13_prefix?(isbn13) click to toggle source

Checks for a valid ISBN13 prefix ISBN13 always starts with 978 or 979. For example: 1000000000012 has a valid check digit, but is not a valid ISBN13. @param [String] isbn13 The ISBN13 to be checked. @return [Boolean] If true then the prefix is valid

# File lib/library_stdnums.rb, line 196
def self.valid_isbn13_prefix?(isbn13)
  isbn13.size == 13 and !!VALID_THIRTEEN_PREFIX.match(isbn13)
end