lib/banktools-se/ocr.rb in banktools-se-2.1.0 vs lib/banktools-se/ocr.rb in banktools-se-2.3.0

- old
+ new

@@ -3,10 +3,11 @@ module BankTools module SE class OCR class InvalidOCR < StandardError; end class OverlongOCR < InvalidOCR; end + class TooShortOCR < InvalidOCR; end class BadPadding < InvalidOCR; end class BadLengthDigit < InvalidOCR; end class BadChecksum < InvalidOCR; end class MustBeNumeric < InvalidOCR; end @@ -26,52 +27,74 @@ number_with_ocr = number + Utils.luhn_checksum(number).to_s length = number_with_ocr.length if length > MAX_LENGTH - raise OverlongOCR, "Bankgiro OCR must be #{MIN_LENGTH} - #{MAX_LENGTH} characters (this one would be #{length} characters)" + raise OverlongOCR, "OCR must be #{MIN_LENGTH} - #{MAX_LENGTH} characters (this one would be #{length} characters)" end number_with_ocr end - def self.to_number(number, length_digit: false, pad: "") - number = number.to_s + def self.to_number(ocr, length_digit: false, pad: "") + ocr = ocr.to_s should_have_length_digit = length_digit strip_padding = pad.to_s - raise MustBeNumeric unless number.match(/\A\d+\z/) - raise BadChecksum unless Utils.valid_luhn?(number) + raise MustBeNumeric unless ocr.match(/\A\d+\z/) + raise BadChecksum unless Utils.valid_luhn?(ocr) + raise TooShortOCR if ocr.length < MIN_LENGTH if should_have_length_digit - length_digit = number[-2] - last_digit_of_actual_length = number.length.to_s[-1] + length_digit = ocr[-2] + last_digit_of_actual_length = ocr.length.to_s[-1] raise BadLengthDigit if length_digit != last_digit_of_actual_length end digits_to_chop = 1 # Checksum. digits_to_chop += 1 if should_have_length_digit if strip_padding.length > 0 expected_padding_end = -digits_to_chop - 1 expected_padding_start = expected_padding_end - strip_padding.length + 1 - raise BadPadding if number[expected_padding_start..expected_padding_end] != strip_padding + raise BadPadding if ocr[expected_padding_start..expected_padding_end] != strip_padding end digits_to_chop += strip_padding.length - number[0...-digits_to_chop] + ocr[0...-digits_to_chop] end - def self.find_all_in_string(string, length_digit: false, pad: "") - string.scan(/\d+/).select { |candidate| + def self.find_all_in_string(string, length_digit: false, pad: "", min_length: 4) + expanded_string = string + " " + string.gsub("\n", "") + " " + string.gsub(";", "") + + numbers = expanded_string.scan(/\d+/) + + expanded_numbers = with_numbers_found_by_removing_prefix_and_postfix(numbers). + reject { |n| n.length < min_length } + + expanded_numbers.select { |candidate| begin to_number(candidate, length_digit: length_digit, pad: pad) true rescue InvalidOCR false end }.uniq + end + + private + + private_class_method \ + def self.with_numbers_found_by_removing_prefix_and_postfix(numbers) + numbers + numbers.flat_map { |number| + 0.upto(number.size).flat_map { |i| + [ + number[0...i], + number[i...number.size], + ] + } + } end end end end