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