Last active
May 16, 2024 04:13
-
-
Save icchan/47d83bacc5113db59fbc to your computer and use it in GitHub Desktop.
Java Credit Card Number Validator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.bubblemix.cardcheck; | |
/** | |
* Validator for credit card numbers | |
* Checks validity and returns card type | |
* | |
* @author ian.chen | |
*/ | |
public class RegexCardValidator { | |
/** | |
* Checks if the field is a valid credit card number. | |
* @param card The card number to validate. | |
* @return Whether the card number is valid. | |
*/ | |
public static CardValidationResult isValid(final String cardIn) { | |
String card = cardIn.replaceAll("[^0-9]+", ""); // remove all non-numerics | |
if ((card == null) || (card.length() < 13) || (card.length() > 19)) { | |
return new CardValidationResult(card,"failed length check"); | |
} | |
if (!luhnCheck(card)) { | |
return new CardValidationResult(card,"failed luhn check"); | |
} | |
CardCompany cc = CardCompany.gleanCompany(card); | |
if (cc == null) return new CardValidationResult(card,"failed card company check"); | |
return new CardValidationResult(card,cc); | |
} | |
/** | |
* Checks for a valid credit card number. | |
* @param cardNumber Credit Card Number. | |
* @return Whether the card number passes the luhnCheck. | |
*/ | |
protected static boolean luhnCheck(String cardNumber) { | |
// number must be validated as 0..9 numeric first!! | |
int digits = cardNumber.length(); | |
int oddOrEven = digits & 1; | |
long sum = 0; | |
for (int count = 0; count < digits; count++) { | |
int digit = 0; | |
try { | |
digit = Integer.parseInt(cardNumber.charAt(count) + ""); | |
} catch(NumberFormatException e) { | |
return false; | |
} | |
if (((count & 1) ^ oddOrEven) == 0) { // not | |
digit *= 2; | |
if (digit > 9) { | |
digit -= 9; | |
} | |
} | |
sum += digit; | |
} | |
return (sum == 0) ? false : (sum % 10 == 0); | |
} | |
/** | |
* Run some tests to show this works | |
* @param args | |
*/ | |
public static void main(String[] args) { | |
String visa = "4444444444444448"; | |
String master = "5500005555555559"; | |
String amex = "371449635398431"; | |
String diners = "36438936438936"; | |
String discover = "6011016011016011"; | |
String jcb = "3566003566003566"; | |
String luhnFail = "1111111111111111"; | |
String invalid = "abcdabcdabcdabcd"; | |
printTest(visa); | |
printTest(master); | |
printTest(amex); | |
printTest(diners); | |
printTest(discover); | |
printTest(jcb); | |
printTest(invalid); | |
printTest(luhnFail); | |
} | |
/** | |
* Check a card number and print the result | |
* @param cardIn | |
*/ | |
private static void printTest(String cardIn) { | |
CardValidationResult result = RegexCardValidator.isValid(cardIn); | |
System.out.println(result.isValid() + " : " + (result.isValid()? result.getCardType().getIssuerName(): "") + " : " + result.getMessage() ); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.bubblemix.cardcheck; | |
/** | |
* enum for card company specifics | |
* | |
*/ | |
public enum CardCompany { | |
VISA ("^4[0-9]{12}(?:[0-9]{3})?$", "VISA"), | |
MASTERCARD ("^5[1-5][0-9]{14}$", "MASTER"), | |
AMEX ("^3[47][0-9]{13}$", "AMEX"), | |
DINERS ("^3(?:0[0-5]|[68][0-9])[0-9]{11}$", "Diners"), | |
DISCOVER ("^6(?:011|5[0-9]{2})[0-9]{12}$", "DISCOVER"), | |
JCB ("^(?:2131|1800|35\\d{3})\\d{11}$", "JCB"); | |
private String regex; | |
private String issuerName; | |
CardCompany(String regex, String issuerName) { | |
this.regex = regex; | |
this.issuerName = issuerName; | |
} | |
public boolean matches(String card) { | |
return card.matches(this.regex); | |
} | |
public String getIssuerName() { | |
return this.issuerName; | |
} | |
/** | |
* get an enum from a card number | |
* @param card | |
* @return | |
*/ | |
public static CardCompany gleanCompany(String card) { | |
for (CardCompany cc : CardCompany.values()){ | |
if (cc.matches(card)) { | |
return cc; | |
} | |
} | |
return null; | |
} | |
/** | |
* get an enum from an issuerName | |
* @param issuerName | |
* @return | |
*/ | |
public static CardCompany gleanCompanyByIssuerName(String issuerName) { | |
for (CardCompany cc : CardCompany.values()){ | |
if (cc.getIssuerName().equals(issuerName)) { | |
return cc; | |
} | |
} | |
return null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.bubblemix.cardcheck; | |
/** | |
* Container for validation result | |
*/ | |
public class CardValidationResult { | |
private boolean valid; | |
private CardCompany cardType; | |
private String error; | |
private String cardNo; | |
public CardValidationResult(String cardNo, String error) { | |
this.cardNo = cardNo; | |
this.error = error; | |
} | |
public CardValidationResult(String cardNo, CardCompany cardType) { | |
this.cardNo = cardNo; | |
this.valid = true; | |
this.cardType = cardType; | |
} | |
public boolean isValid() { | |
return valid; | |
} | |
public CardCompany getCardType() { | |
return cardType; | |
} | |
public String getError() { | |
return error; | |
} | |
public String cardNo() { | |
return this.cardNo; | |
} | |
public String getMessage() { | |
return cardNo + " >> " + ((valid) ? ("card: " + this.cardType ): error) ; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment