Thursday, September 24, 2009

Credit Card Processing

Credit Card Processing from Problem Set 2005-2006

http://www.socalcontest.org/current/index.shtml

Solution :

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <fstream>
#include <cctype>
#include <sstream>
#include <vector>

using namespace std;

string util_trim_right( const string& s, const string& delim = " " ) {
string temp( s );
string::size_type o = temp.find_last_not_of( delim );
if ( o == string::npos )
return temp;
else
return temp.erase( temp.find_last_not_of( delim ) + 1 );
}

string util_trim_left( const string& s, const string& delim = " " ) {
string temp( s );
return temp.erase( 0, s.find_first_not_of( delim ) );
}

vector< string > util_tokenize_string( const string& str, const string& del = "," ) {
vector< string > result;
string::size_type start = 0;
string::size_type end = str.find_first_of( del, start );
string::size_type length = str.length();
string word;

while ( string::npos != end && end < length ) {
word = str.substr( start, end - start );
result.push_back( word );
start = end + 1;
end = str.find_first_of( del, start );
}

end = str.find_last_of( del ) + 1;
result.push_back( str.substr( end ) );

return result;
}

void util_delete_all_white_space( string& s ) {
s.erase( remove( s.begin(), s.end(), ' ' ), s.end() );
}

bool util_is_all_white_space( const string& s ) {
for ( unsigned o = 0, o_end = s.length(); o < o_end; ++o )
if ( s[ o ] != ' ' )
return false;

return true;
}


class Customer {
public :
string cu_first_name;
string cu_last_name;
string cu_address;
string cu_city;
string cu_state;
string cu_zipcode;
string cu_ssn;
string cu_credit_1;
string cu_credit_2;
string cu_credit_3;
char cu_literal_semicolon;

public :
// bussiness rule 1
bool cu_test_leading_white_space_and_null() const;

// bussiness rule 2
bool cu_test_byte_field_isdigit_isalpha() const;

// bussiness rule 3
bool cu_test_credit_score() const;

// bussiness rule 4
bool cu_test_credit_score_mean() const;

void cu_show_customer_info() const;

};


void Customer::cu_show_customer_info() const {
cout << "1." << cu_first_name << "\n";
cout << "2." << cu_last_name << "\n";
cout << "3." << cu_address << "\n";
cout << "4." << cu_city << "\n";
cout << "5." << cu_state << "\n";
cout << "6." << cu_zipcode << "\n";
cout << "7." << cu_ssn << "\n";
cout << "8." << cu_credit_1 << "\n";
cout << "9." << cu_credit_2 << "\n";
cout << "10." << cu_credit_3 << "\n";
}

bool Customer::cu_test_credit_score() const {
istringstream o1( cu_credit_1, istringstream::in );
istringstream o2( cu_credit_2, istringstream::in );
istringstream o3( cu_credit_3, istringstream::in );

int val_1, val_2, val_3;
o1 >> val_1;
o2 >> val_2;
o3 >> val_3;

if (
val_1 < 400 ||
val_2 < 400 ||
val_3 < 400 ) {

return false;
}

return true;
}

bool Customer::cu_test_credit_score_mean() const {
istringstream o1( cu_credit_1, istringstream::in );
istringstream o2( cu_credit_2, istringstream::in );
istringstream o3( cu_credit_3, istringstream::in );

int val_1, val_2, val_3;
o1 >> val_1;
o2 >> val_2;
o3 >> val_3;

double mean = static_cast< double >( val_1 + val_2 + val_3 ) / 3.0;
if ( mean < 500 ) {
return false;
}

return true;
}

bool Customer::cu_test_byte_field_isdigit_isalpha() const {

// check literal_semicolon
if ( cu_literal_semicolon != ';' )
return false;

// check byte field
if ( cu_state.length() != 2 || cu_zipcode.length() != 5 )
return false;

// check city for non-alphanumeric
for ( unsigned o = 0, o_end = cu_city.length(); o < o_end; ++o ) {
if ( isdigit( cu_city[ o ] ) == false && isalpha( cu_city[ o ] ) == false )
return false;
}

// check state for only alphabetic
for ( unsigned o = 0, o_end = cu_state.length(); o < o_end; ++o ) {
if ( isalpha( cu_state[ o ] ) == false )
return false;
}

// check zipcode for only numeric
for ( unsigned o = 0, o_end = cu_zipcode.length(); o < o_end; ++o ) {
if ( isdigit( cu_zipcode[ o ] ) == false )
return false;
}

// check ssn for only numeric
for ( unsigned o = 0, o_end = cu_ssn.length(); o < o_end; ++o ) {
if ( isdigit( cu_ssn[ o ] ) == false )
return false;
}

unsigned CREDIT_DIGITS = 3;
// check credit_1, credit_2, credit_3 for only numeric
for ( unsigned o = 0; o < CREDIT_DIGITS; ++o ) {
if (
isdigit( cu_credit_1[ o ] ) == false ||
isdigit( cu_credit_2[ o ] ) == false ||
isdigit( cu_credit_3[ o ] ) == false ) {

return false;
}
}

// check credit_1, credit_2, credit_3 for valid range ( 200 - 800 )
istringstream o1( cu_credit_1, istringstream::in );
istringstream o2( cu_credit_2, istringstream::in );
istringstream o3( cu_credit_3, istringstream::in );

int val_1, val_2, val_3;
o1 >> val_1;
o2 >> val_2;
o3 >> val_3;

if (
val_1 < 200 || val_1 > 800 ||
val_2 < 200 || val_2 > 800 ||
val_3 < 200 || val_3 > 800 ) {
return false;
}

return true;
}

bool Customer::cu_test_leading_white_space_and_null() const {

// check for NULL character
if ( cu_literal_semicolon == ' ' )
return false;

// check for NULL string

if (
util_is_all_white_space( cu_first_name ) == true ||
util_is_all_white_space( cu_last_name ) == true ||
util_is_all_white_space( cu_address ) == true ||
util_is_all_white_space( cu_city ) == true ||
util_is_all_white_space( cu_state ) == true ||
util_is_all_white_space( cu_zipcode ) == true ||
util_is_all_white_space( cu_ssn ) == true ||
util_is_all_white_space( cu_credit_1 ) == true ||
util_is_all_white_space( cu_credit_2 ) == true ||
util_is_all_white_space( cu_credit_3 ) == true ) {

return false;
}

// check for leading white space
if (
cu_first_name[ 0 ] == ' ' ||
cu_last_name[ 0 ] == ' ' ||
cu_address[ 0 ] == ' ' ||
cu_city[ 0 ] == ' ' ||
cu_state[ 0 ] == ' ' ||
cu_zipcode[ 0 ] == ' ' ) {

return false;
}

return true;
}

vector< Customer > main_prog_get_data_from_file( const char* file_name ) {
ifstream o( file_name );
string oneline;
vector< Customer > cus_vec;

while ( getline( o, oneline ) ) {

cout << oneline << endl;
Customer cus;
string temp; // use for a_c_s_z string

// get the last character
cus.cu_literal_semicolon = oneline[ 89 ];

for ( unsigned o = 0; o < 12; ++o ) {
cus.cu_first_name.push_back( oneline[ o ] );
}

for ( unsigned o = 12; o < 29; ++o ) {
cus.cu_last_name.push_back( oneline[ o ] );
}

for ( unsigned o = 30; o < 71; ++o ) {
temp.push_back( oneline[ o ] );
}

for ( unsigned o = 71; o < 79; ++o ) {
cus.cu_ssn.push_back( oneline[ o ] );
}

for ( unsigned o = 80; o < 83; ++o ) {
cus.cu_credit_1.push_back( oneline[ o ] );
}

for ( unsigned o = 83; o < 86; ++o ) {
cus.cu_credit_2.push_back( oneline[ o ] );
}

for ( unsigned o = 86; o < 89; ++o ) {
cus.cu_credit_3.push_back( oneline[ o ] );
}


/* trim right for :
1. first name
2. last name
*/
cus.cu_first_name = util_trim_right( cus.cu_first_name );
cus.cu_last_name = util_trim_right( cus.cu_last_name );

/*
Since we need to have enough commas( 3 )
to handle the tokenizer, we need to test :
1. All whitespace
2. No comma
3. Not enough comma

One of these 3 fails, we will set all the 4 field :
- cu_address
- cu_city
- cu_state
- cu_zipcode
to all whitespace so it will fail later on
business rule 1
*/
bool is_all_white_space = true;
for ( unsigned o = 0, o_end = temp.length(); o < o_end; ++o ) {
if ( temp[ o ] != ' ' )
is_all_white_space = false;
}

bool is_no_comma_separator = true;
for ( unsigned o = 0, o_end = temp.length(); o < o_end; ++o ) {
if ( temp[ o ] == ',' )
is_no_comma_separator = false;
}

bool is_not_enough_commad = false;
unsigned comma_count = 0;
for ( unsigned o = 0, o_end = temp.length(); o < o_end; ++o ) {
if ( temp[ o ] == ',' )
comma_count++;
}

if ( comma_count < 3 )
is_not_enough_commad = true;

if ( is_no_comma_separator == true ||
is_all_white_space == true ||
is_no_comma_separator == true ) {
fill_n( cus.cu_address.begin(), cus.cu_address.length(), ' ' );
fill_n( cus.cu_city.begin(), cus.cu_city.length(), ' ' );
fill_n( cus.cu_state.begin(), cus.cu_state.length(), ' ' );
fill_n( cus.cu_zipcode.begin(), cus.cu_zipcode.length(), ' ' );
} else {

vector< string > address_city_state_zipcode;
address_city_state_zipcode = util_tokenize_string( temp );
/* trim right for :
3. address
4. city
5. state
6. zipcode
*/
cus.cu_address = util_trim_right( address_city_state_zipcode[ 0 ] );
cus.cu_city = util_trim_right( address_city_state_zipcode[ 1 ] );
cus.cu_state = util_trim_right( address_city_state_zipcode[ 2 ] );
cus.cu_zipcode = util_trim_right( address_city_state_zipcode[ 3 ] );
}

/* delete all white space for :
1. ssn
2. credit 1
3. credit 2
4. credit 3
*/
util_delete_all_white_space( cus.cu_ssn );
util_delete_all_white_space( cus.cu_credit_1 );
util_delete_all_white_space( cus.cu_credit_2 );
util_delete_all_white_space( cus.cu_credit_3 );


cus_vec.push_back( cus );
}

return cus_vec;
}

void main_prog_test_all_customers( const vector< Customer >& v ) {
for ( unsigned o = 0, o_end = v.size(); o < o_end; ++o ) {
cout << "\n\n --- Customer " << o + 1 << "\n";

bool status = true;
status = v[ o ].cu_test_leading_white_space_and_null();
cout << "Status 1 " << status << endl;

status = v[ o ].cu_test_byte_field_isdigit_isalpha();
cout << "Status 2 " << status << endl;

status = v[ o ].cu_test_credit_score();
cout << "Status 3 " << status << endl;

status = v[ o ].cu_test_credit_score_mean();
cout << "Status 4 " << status << endl;
}
}

int main() {

vector< Customer > v;
v = main_prog_get_data_from_file( "in1.txt" );
main_prog_test_all_customers( v );
return 0;
}