Validating ISBN: Regex question

Hi!

I’m using the following method to validate an ISBN, remove any ’ ’
or ‘-’ from it and and change ‘x’ to ‘X’.

def validate_isbn!
match = /(\d)[- ]?(\d)[- ]?(\d)[- ]?(\d)[- ]?(\d)[- ]?(\d)[- ]?(\d)[- ]?(\d)[- ]?(\d)[- ]?([0-9xX])/.match(@isbn)
if match == nil
return ‘ISBN pattern mismatch’
end
checksum = 0
@isbn = ‘’
for i in 1…10
case match[i]
when ‘X’, ‘x’
checksum += 10
@isbn += ‘X’
else
checksum += (11 - i) * match[i].to_i
@isbn += match[i]
end
end
(checksum.remainder(11) == 0 ? ‘’ : ‘in’) + ‘valid checksum’
end

I’m not to happy about the lenghty regex but I don’t see how to make
it shorter because using

match = /(\d[- ]?){9,9}([0-9xX])/.match(@isbn)

is not possible - it does not split the ISBN into it’s digits.

Is there any elegant solution to this?

Josef ‘Jupp’ Schugt

> match = /(\d[- ]?){9,9}([0-9xX])/.match(@isbn)

Well, if you want to use this regexp replace your

   for i in 1 .. 10

with

   match[0].split(/[- ]?/).each_with_index do |x, i|
      # warning `i' will take the values 0 .. 9
   end

Guy Decoux

match[0].split(/[- ]?/).each_with_index do |x, i|
# warning `i’ will take the values 0 … 9
end

Merci bien. Not only does this remove the need of a lengthy pattern,
it also allows for a more readable implementation. I post it because
IIRC some people have shown interest in validating ISBNs.

def validate_isbn!
match = /(\d[- ]?){9,9}([0-9xX])/.match(@isbn)
if match == nil
return ‘ISBN pattern mismatch’
end
@isbn = ‘’
checksum = 0
match[0].split(/[- ]?/).each_with_index { |char, index|
case char
when ‘X’, ‘x’
checksum += 10
@isbn += ‘X’
else
checksum += (10 - index) * char.to_i
@isbn += char
end
}
(checksum.remainder(11) == 0 ? ‘’ : ‘in’) + ‘valid checksum’
end

Josef ‘Jupp’ Schugt

···

On Sun, 27 Oct 2002 02:00:55 +0900, Guy Decoux (ts) decoux@moulon.inra.fr wrote: