forked from square/luhnybin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathluhn.rb
85 lines (73 loc) · 1.77 KB
/
luhn.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
DOUBLE_DIGITS = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
class Luhn
def test_it a, start_at, max_len
total = 0
double_digit = false
i = start_at + max_len - 1
while i >= start_at
total += double_digit ? DOUBLE_DIGITS[a[i]] : a[i]
double_digit = !double_digit
i -= 1
end
total % 10 == 0
end
def mask s
mirror = s.unpack('c*')
masked = nil
i = 0
digit_count = 0
mask_offset = -1
digits = []
len = mirror.length
while i < len
c = mirror[i]
if c >= 48 and c <= 57 #between 0 and 9
digit_count += 1
digits << c - 48
if digit_count >= 14
the_len = digit_count < 16 ? digit_count : 16
while the_len >= 14
start_at = digit_count - the_len
if test_it(digits, start_at, the_len)
masked = mirror[0..-1] if not masked
mask_len = the_len
j = i
while mask_len > 0 && j > mask_offset
mc = mirror[j]
if mc >= 48 and mc <= 57 #between 0 and 9
masked[j] = 88 #X
mask_len -= 1
end
j -= 1
end
mask_offset = i if the_len == 16
end
the_len -= 1
end
end
elsif c != 45 and c != 32 #not - or space
if digit_count > 0
digit_count = 0
digits = []
end
end
i += 1
end
masked ? masked.pack('c*') : s
end
def tap_stdin
n_repeats = ARGV[0] ? ARGV[0].to_i : 1
if n_repeats > 1
lines = STDIN.readlines
n_repeats.times do
lines.each do |s|
puts mask(s)
end
end
else
STDIN.each do |s|
puts mask(s)
end
end
end
end