java 用于确定 Android 中信用卡的正则表达式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28207252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Regex for determining credit cards in Android
提问by AIntel
I'm really new to regex but I think my problem might go beyond that at the moment. As the title says, I'm trying to determine if a credit card is visa, amex, master card etc.
我对正则表达式真的很陌生,但我认为目前我的问题可能不止于此。正如标题所说,我试图确定信用卡是否是签证、美国运通卡、万事达卡等。
I looked at this post which gave the regular expression for each of the card types:
我查看了这篇文章,其中给出了每种卡片类型的正则表达式:
How do you detect Credit card type based on number?
This is the code I then used but it doesn't do anything at all:
这是我然后使用的代码,但它根本没有做任何事情:
etCCNum.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.d("DEBUG", "beforeTextChanged : "+s);
}
@Override
public void afterTextChanged(Editable s) {
Pattern pattern = Pattern.compile("^6(?:011|5[0-9]{2})[0-9]{3,}$");
Log.d("DEBUG", "afterTextChanged : "+s);
String ccNum = s.toString();
Matcher matcher = pattern.matcher(ccNum);
if(matcher.matches()){
Log.d("DEBUG", "afterTextChanged : discover");
}
}
});
The regexp in the pattern.compile function is for determining Discover cards according to the post above. I've noticed that I really can't get anything to work other than the "^" in regex (i.e ("^4" - visa, "^6001" discover) however this is obviously not sufficient in the case of editing for example. Any ideas what's up? I thought this could be an issue with my Java, but I am running Java 7
pattern.compile 函数中的正则表达式用于根据上面的帖子确定发现卡。我注意到除了正则表达式中的“^”(即(“^4” - 签证,“^ 6001”发现)之外,我真的无法获得任何工作,但是在编辑的情况下,这显然是不够的示例。有什么想法吗?我认为这可能是我的 Java 的问题,但我正在运行 Java 7
I might want to make this a new question, but I am also wondering how regex can be used to get spacing correct for various credit cards even if a user goes back and edits the number (xxxx xxxx xxxx xxxx)
我可能想提出一个新问题,但我也想知道如何使用正则表达式来使各种信用卡的间距正确,即使用户返回并编辑数字 (xxxx xxxx xxxx xxxx)
EDIT: Added the DEBUG log from above. My input is a few digits that should associate with certain credit cards. Currently I am using Eagle Eye's code provided below (which should also work for detecting that the input is ONE of the card types):
编辑:从上面添加了调试日志。我的输入是一些应该与某些信用卡相关联的数字。目前我正在使用下面提供的 Eagle Eye 的代码(它也应该用于检测输入是一种卡片类型):
final ArrayList listOfPattern=new ArrayList();
最终 ArrayList listOfPattern=new ArrayList();
String ptVisa = "^4[0-9]{6,}$";
listOfPattern.add(ptVisa);
String ptMasterCard = "^5[1-5][0-9]{5,}$";
listOfPattern.add(ptMasterCard);
String ptAmeExp = "^3[47][0-9]{5,}$";
listOfPattern.add(ptAmeExp);
String ptDinClb = "^3(?:0[0-5]|[68][0-9])[0-9]{4,}$";
listOfPattern.add(ptDinClb);
String ptDiscover = "^6(?:011|5[0-9]{2})[0-9]{3,}$";
listOfPattern.add(ptDiscover);
String ptJcb = "^(?:2131|1800|35[0-9]{3})[0-9]{3,}$";
listOfPattern.add(ptJcb);
etCCNum.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.d("DEBUG", "beforeTextChanged : "+s);
}
@Override
public void afterTextChanged(Editable s) {
Log.d("DEBUG", "afterTextChanged : "+s);
String ccNum = s.toString();
for(String p:listOfPattern){
if(ccNum.matches(p)){
Log.d("DEBUG", "afterTextChanged : discover");
break;
}
}
}
});
Log:
日志:
01-29 15:16:41.932 26194-26194/com.x.x D/DEBUG﹕ beforeTextChanged :
01-29 15:16:41.933 26194-26194/com.x.x D/DEBUG﹕ afterTextChanged : 4
01-29 15:16:46.815 26194-26194/com.x.x D/DEBUG﹕ beforeTextChanged : 4
01-29 15:16:46.816 26194-26194/com.x.x D/DEBUG﹕ afterTextChanged :
01-29 15:16:50.925 26194-26194/com.x.x D/DEBUG﹕ beforeTextChanged :
01-29 15:16:50.926 26194-26194/com.x.x D/DEBUG﹕ afterTextChanged : 6
01-29 15:16:51.542 26194-26194/com.x.x D/DEBUG﹕ beforeTextChanged : 6
01-29 15:16:51.543 26194-26194/com.x.x D/DEBUG﹕ afterTextChanged : 60
01-29 15:16:51.883 26194-26194/com.x.x D/DEBUG﹕ beforeTextChanged : 60
01-29 15:16:51.883 26194-26194/com.x.x D/DEBUG﹕ afterTextChanged : 600
01-29 15:16:52.928 26194-26194/com.x.x D/DEBUG﹕ beforeTextChanged : 600
01-29 15:16:52.929 26194-26194/com.x.x D/DEBUG﹕ afterTextChanged : 6001
01-29 15:16:55.781 26194-26194/com.x.x D/DEBUG﹕ beforeTextChanged : 6001
01-29 15:16:55.782 26194-26194/com.x.x D/DEBUG﹕ afterTextChanged : 600
01-29 15:16:56.206 26194-26194/com.x.x D/DEBUG﹕ beforeTextChanged : 600
01-29 15:16:56.206 26194-26194/com.x.x D/DEBUG﹕ afterTextChanged : 60
01-29 15:16:57.659 26194-26194/com.x.x D/DEBUG﹕ beforeTextChanged : 60
01-29 15:16:57.660 26194-26194/com.x.x D/DEBUG﹕ afterTextChanged : 605
01-29 15:16:59.297 26194-26194/com.x.x D/DEBUG﹕ beforeTextChanged : 605
01-29 15:16:59.298 26194-26194/com.x.x D/DEBUG﹕ afterTextChanged : 60
01-29 15:16:59.527 26194-26194/com.x.x D/DEBUG﹕ beforeTextChanged : 60
01-29 15:16:59.527 26194-26194/com.x.x D/DEBUG﹕ afterTextChanged : 6
01-29 15:17:00.314 26194-26194/com.x.x D/DEBUG﹕ beforeTextChanged : 6
01-29 15:17:00.314 26194-26194/com.x.x D/DEBUG﹕ afterTextChanged : 65
You'd expect the log "discover" to come out a few times for the different digits I've entered. The above log shows me typing in the first few digits of a visa card and a discover card.
对于我输入的不同数字,您会期望日志“发现”出现几次。上面的日志显示我输入了签证卡和发现卡的前几位数字。
EDIT ANSWER FOUND: I simply wasn't typing in enough digits for the card to be recognized!
编辑答案发现:我只是没有输入足够的数字来识别卡!
回答by Vilas
According to one of the answers in the thread, The cards can be validated based on following data.
根据线程中的一个答案,可以根据以下数据验证卡。
Visa:^4[0-9]{6,}$
Visa card numbers start with a 4.
Visa:^4[0-9]{6,}$
Visa 卡号以 4 开头。
MasterCard:^5[1-5][0-9]{5,}$
MasterCard numbers start with the numbers 51 through 55, but this will only detect MasterCard credit cards; there are other cards issued using the MasterCard system that do not fall into this IIN range.
MasterCard:^5[1-5][0-9]{5,}$
MasterCard 号码以数字 51 到 55 开头,但这只会检测 MasterCard 信用卡;还有其他使用万事达卡系统发行的卡不属于此 IIN 范围。
American Express:^3[47][0-9]{5,}$
American Express card numbers start with 34 or 37.
美国运通:^3[47][0-9]{5,}$
美国运通卡号以 34 或 37 开头。
Diners Club:^3(?:0[0-5]|[68][0-9])[0-9]{4,}$
Diners Club card numbers begin with 300 through 305, 36 or 38. There are Diners Club cards that begin with 5 and have 16 digits. These are a joint venture between Diners Club and MasterCard, and should be processed like a MasterCard.
Diners Club:^3(?:0[0-5]|[68][0-9])[0-9]{4,}$
Diners Club 卡号以 300 到 305、36 或 38 开头。有一些 Diners Club 卡以 5 开头并有 16 位数字。这些是大来卡和万事达卡的合资企业,应该像万事达卡一样处理。
Discover:^6(?:011|5[0-9]{2})[0-9]{3,}$
Discover card numbers begin with 6011 or 65.
Discover:^6(?:011|5[0-9]{2})[0-9]{3,}$
Discover 卡号以 6011 或 65 开头。
JCB:^(?:2131|1800|35[0-9]{3})[0-9]{3,}$
JCB cards begin with 2131, 1800 or 35.
JCB:^(?:2131|1800|35[0-9]{3})[0-9]{3,}$
JCB 卡以 2131、1800 或 35 开头。
So you need to create separate pattern for each case. You can do as follows.
因此,您需要为每种情况创建单独的模式。您可以执行以下操作。
ArrayList<String> listOfPattern=new ArrayList<String>();
String ptVisa = "^4[0-9]{6,}$";
listOfPattern.add(ptVisa);
String ptMasterCard = "^5[1-5][0-9]{5,}$";
listOfPattern.add(ptMasterCard);
String ptAmeExp = "^3[47][0-9]{5,}$";
listOfPattern.add(ptAmeExp);
String ptDinClb = "^3(?:0[0-5]|[68][0-9])[0-9]{4,}$";
listOfPattern.add(ptDinClb);
String ptDiscover = "^6(?:011|5[0-9]{2})[0-9]{3,}$";
listOfPattern.add(ptDiscover);
String ptJcb = "^(?:2131|1800|35[0-9]{3})[0-9]{3,}$";
listOfPattern.add(ptJcb);
}
and then,
接着,
@Override
public void afterTextChanged(Editable s) {
Log.d("DEBUG", "afterTextChanged : "+s);
String ccNum = s.toString();
for(String p:listOfPattern){
if(ccNum.matches(p)){
Log.d("DEBUG", "afterTextChanged : discover");
break;
}
}
}
And for your last question, The following thread should help you.
对于您的最后一个问题,以下线程应该可以帮助您。
Format credit card in edit text in android
EDIT:
编辑:
If the card number is 16 digits for example, After applying the logic to add spaces after 4 digits, you need to remove those spaces when you process the actual card number. Then only the above logic will work.
以卡号为16位为例,应用4位后加空格的逻辑后,在处理实际卡号时需要去掉这些空格。那么只有上面的逻辑会起作用。
Hope this helps.
希望这可以帮助。
回答by Pinakin
Use following class to validate you card.
使用以下类来验证您的卡。
public class Validator {
public static final byte VISA = 0;
public static final byte MASTERCARD = 1;
public static final byte AMEX = 2;
public static final byte DINERS_CLUB = 3;
public static final byte CARTE_BLANCHE = 4;
public static final byte DISCOVER = 5;
public static final byte ENROUTE = 6;
public static final byte JCB = 7;
public static boolean validate(final String credCardNumber, final byte type) {
String creditCard = credCardNumber.trim();
boolean applyAlgo = false;
switch (type) {
case VISA:
// VISA credit cards has length 13 - 15
// VISA credit cards starts with prefix 4
if (creditCard.length() >= 13 && creditCard.length() <= 16
&& creditCard.startsWith("4")) {
applyAlgo = true;
}
break;
case MASTERCARD:
// MASTERCARD has length 16
// MASTER card starts with 51, 52, 53, 54 or 55
if (creditCard.length() == 16) {
int prefix = Integer.parseInt(creditCard.substring(0, 2));
if (prefix >= 51 && prefix <= 55) {
applyAlgo = true;
}
}
break;
case AMEX:
// AMEX has length 15
// AMEX has prefix 34 or 37
if (creditCard.length() == 15
&& (creditCard.startsWith("34") || creditCard
.startsWith("37"))) {
applyAlgo = true;
}
break;
case DINERS_CLUB:
case CARTE_BLANCHE:
// DINERSCLUB or CARTEBLANCHE has length 14
// DINERSCLUB or CARTEBLANCHE has prefix 300, 301, 302, 303, 304,
// 305 36 or 38
if (creditCard.length() == 14) {
int prefix = Integer.parseInt(creditCard.substring(0, 3));
if ((prefix >= 300 && prefix <= 305)
|| creditCard.startsWith("36")
|| creditCard.startsWith("38")) {
applyAlgo = true;
}
}
break;
case DISCOVER:
// DISCOVER card has length of 16
// DISCOVER card starts with 6011
if (creditCard.length() == 16 && creditCard.startsWith("6011")) {
applyAlgo = true;
}
break;
case ENROUTE:
// ENROUTE card has length of 16
// ENROUTE card starts with 2014 or 2149
if (creditCard.length() == 16
&& (creditCard.startsWith("2014") || creditCard
.startsWith("2149"))) {
applyAlgo = true;
}
break;
case JCB:
// JCB card has length of 16 or 15
// JCB card with length 16 starts with 3
// JCB card with length 15 starts with 2131 or 1800
if ((creditCard.length() == 16 && creditCard.startsWith("3"))
|| (creditCard.length() == 15 && (creditCard
.startsWith("2131") || creditCard
.startsWith("1800")))) {
applyAlgo = true;
}
break;
default:
throw new IllegalArgumentException();
}
if (applyAlgo) {
return validate(creditCard);
}
return false;
}
public static boolean validate(String creditCard) {
// 4 9 9 2 7 3 9 8 7 1 6
// 6
// 1 x 2 = 2 = (0 + 2) = 2
// 7
// 8 x 2 = 16 = (1 + 6) = 7
// 9
// 3 x 2 = 6 = (0 + 6) = 6
// 7
// 2 x 2 = 4 = (0 + 4) = 4
// 9
// 9 X 2 = 18 = (1 + 8) = 9
// 4
// 6+2+7+7+9+6+7+4+9+9+4 = 70
// return 0 == (70 % 10)
int sum = 0;
int length = creditCard.length();
for (int i = 0; i < creditCard.length(); i++) {
if (0 == (i % 2)) {
sum += creditCard.charAt(length - i - 1) - '0';
} else {
sum += sumDigits((creditCard.charAt(length - i - 1) - '0') * 2);
}
}
return 0 == (sum % 10);
}
private static int sumDigits(int i) {
return (i % 10) + (i / 10);
}
public final static boolean isValidEmail(CharSequence target) {
return !TextUtils.isEmpty(target) && android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches();
}
}
}