forked from square/luhnybin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
run.cpp
139 lines (112 loc) · 4.36 KB
/
run.cpp
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/***********************************************************************
* Copyright (C) 2012 Andrei Taranchenko
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**********************************************************************/
#ifndef test_c
#define test_c
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <ctype.h>
#include <sstream>
#include <functional>
#endif
using namespace std;
const int MIN_LEN = 14;
const int MAX_LEN = 16;
// forward declarations
string process(const string & data);
bool is_valid(const string & data, string::const_iterator itr1, string::const_iterator itr2);
int get_digit_count(const string & cc_no);
int main(int argc, char* argv[]) {
// read standard input, line by line
string data;
while(cin) {
getline(cin, data);
cout << process(data) << endl;
};
return 0;
}
//----------------------------------------------------------------------
bool is_invalid_char(const char ch) {
return !isdigit(ch) && ch != '-' && ch != ' ';
}
//----------------------------------------------------------------------
void mask(const string & data, string & result, string::const_iterator itr1, string::const_iterator itr2) {
int digit_count = count_if(itr1, itr2, ::isdigit);
int invalid_char_count = count_if(itr1, itr2, is_invalid_char);
while (invalid_char_count == 0 && digit_count <= MAX_LEN && itr2 <= data.end()) {
const bool isvalid = is_valid(data, itr1, itr2);
if (isvalid) {
string::iterator mask_begin = result.begin() + distance(data.begin(), itr1);
string::iterator mask_end = result.begin() + distance(data.begin(), itr2);
replace_if(mask_begin, mask_end, ::isdigit, 'X');
}
++itr2;
digit_count = count_if(itr1, itr2, ::isdigit);
invalid_char_count = count_if(itr1, itr2, is_invalid_char);
}
}
//----------------------------------------------------------------------
string process(const string & data) {
string result(data);
string::const_iterator itr1 = data.begin();
string::const_iterator itr2 = itr1 + MIN_LEN;
while (itr2 <= data.end()) {
mask(data, result, itr1, itr2);
++itr1;
++itr2;
}
return result;
}
//----------------------------------------------------------------------
bool is_valid(const string & data, string::const_iterator itr1, string::const_iterator itr2) {
const int digit_count = count_if(itr1, itr2, ::isdigit);
if (digit_count < MIN_LEN || digit_count > MAX_LEN) {
return false;
}
vector<int> digits;
// get digits-only vector from raw character input
for (itr1; itr1 < itr2; ++itr1) {
char ch = *itr1;
if (isdigit(ch)) {
digits.push_back(atoi(&ch));
}
}
vector<int> luhn_product;
// for translating digits to strings
std::stringstream ss;
// go in reverse
for (vector<int>::reverse_iterator itr = digits.rbegin(); itr < digits.rend(); ++itr) {
int digit = *itr;
const int dist = distance(digits.rbegin(), itr);
if (dist % 2 != 0) { // one of every other digits
digit = digit * 2;
}
// convert the digit to string, so we can split digits
ss.str("");
ss << digit;
const string as_string = ss.str();
// add the separate digits, in case there is more than one, to luhn container
for (int n = 0; n < as_string.size(); ++n) {
char ch = as_string[n];
int num = atoi(&ch);
luhn_product.push_back(num);
}
}
// w00t
const int luhn_sum = accumulate(luhn_product.begin(), luhn_product.end(), 0);
return luhn_sum % 10 == 0;
}