在Android中确定信用卡的正则表达式

12

我对正则表达式非常陌生,但我认为目前我的问题可能超出了正则表达式的范围。如标题所说,我正在尝试确定信用卡是 Visa、Amex、MasterCard 等类型。

我查看了这篇文章,其中提供了每种卡片类型的正则表达式:

如何根据号码检测信用卡类型?

接着我使用了下面这段代码,但它什么也没做:

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");
               }

            }
        });

pattern.compile函数中的正则表达式是用来根据上面的帖子确定Discover卡的。我注意到除了正则表达式中的"^"之外,我确实无法让任何其他内容起作用(例如("^4"表示Visa,"^6001"表示Discover),但在编辑时这显然是不够的。有什么想法吗?我以为这可能是我的Java出了问题,但我正在运行Java 7。

也许我想把这变成一个新问题,但我也想知道如何使用正则表达式使各种信用卡的间距正确,即使用户回去编辑数字(xxxx xxxx xxxx xxxx)。

编辑:添加了上面的DEBUG日志。我的输入是几个数字,应该与某些信用卡关联。目前我正在使用Eagle Eye提供的代码(它也适用于检测输入是这些卡类型之一):

final 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;
            }
        }

    }
});

记录:

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

你会期望"discover"这个日志会针对我输入的不同数字出现几次。上面的日志显示我正在输入Visa信用卡和Discover信用卡的前几位数字。

编辑:我只是没有输入足够多的数字,所以无法识别信用卡!


你已经链接到一个完全回答了你问题各个方面的问题。 - njzk2
我的问题是为什么那段代码对我不起作用。我认为问题出在Java或Android Studio上。 - AIntel
(另外,你的代码只测试Discover卡) - njzk2
没错,它现在是正确的,我已经单独测试了其他卡片。我现在正在使用EagleEye的代码,它只是检查信用卡号码是否与任何模式匹配,但日志仍然显示“发现”。 - AIntel
哦,哇,你说得完全正确。谢谢! - AIntel
显示剩余2条评论
2个回答

22
根据主题中的一个回答,这些卡可以基于以下数据进行验证。
Visa:^4 [0-9] {6,}$ Visa 卡号以 4 开头。
MasterCard:^5 [1-5] [0-9] {5,}$ MasterCard 号码以数字 51 到 55 开头,但这只会检测 MasterCard 信用卡; 还有其他使用 MasterCard 系统发行但不在此 IIN 范围内的卡片。
美国运通:^3 [47] [0-9] {5,}$ 美国运通卡号以 34 或 37 开头。
Diners Club:^3 ?: (0 [0-5] | [68] [0-9]) [0-9] {4,}$ Diners Club 卡号从 300 到 305、36 或 38 开始。有一种以 5 开头且有 16 位数字的 Diners Club 卡。这是 Diners Club 和 MasterCard 的合资企业,应像 MasterCard 一样处理。
Discover:^6 ?: (011 | 5 [0-9] {2}) [0-9] {3,}$ Discover 卡号以 6011 或 65 开头。
JCB:^(?:2131|1800|35[0-9]{3})[0-9]{3,}$ JCB 卡片以 2131、1800 或 35 开头。
因此,您需要为每种情况创建单独的模式。您可以按如下方式执行。
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);
}

接着,

@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;
      }
   }
}

对于您的最后一个问题,以下帖子应该会对您有所帮助。

在Android中在编辑文本中格式化信用卡

编辑:

如果卡号是16位数字,请在每4位数字后添加空格的逻辑被应用后,在处理实际卡号时需要将这些空格删除。那么上述逻辑才能正常工作。

希望这可以帮到您。


1
这对我不起作用。它从未进入if语句。 - AIntel
抱歉,我的错误。我已经更新了答案。您需要从卡号中删除添加的空格。 - Vilas
2
虽然您说得没错,不应该有空格,但我输入信用卡号时没有加空格,它仍然无法工作。是否有可能某些正则表达式在Java 7上不起作用? - AIntel
1
如果我想要检查一个信用卡号属于 Visa 还是 Master,该怎么做? - Nathiel Barros
1
Vilas,你能否更新它以支持银联和其余网络? - Rana Ali Waseem

-1
使用以下类来验证您的卡片。
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();
}

}


“applyAlgo”变量基本上是多余的,因为当大多数设置它为“true”的路径未被采用时,您会抛出异常,并且在其他情况下应用它也不会有任何影响。我也非常反对缩写这个词。这个词是“algorithm”,来自一个专有名词。 - user207421
1
这不是我想做的事情,我正在尝试弄清楚用户输入的信用卡类型。我已经实现了一个验证算法来确定信用卡是否有效。 - AIntel
// VISA信用卡长度为13-15。不。 - njzk2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接