用于在 Android 中确定信用卡的正则表达式 [重复]

Posted

技术标签:

【中文标题】用于在 Android 中确定信用卡的正则表达式 [重复]【英文标题】:Regex for determining credit cards in Android [duplicate] 【发布时间】:2015-03-28 05:43:13 【问题描述】:

我对正则表达式真的很陌生,但我认为我的问题目前可能不止于此。正如标题所说,我正在尝试确定信用卡是visa、amex、master card等。

我看了这篇文章,它给出了每种卡片类型的正则表达式:

How do you detect Credit card type based on number?

这是我随后使用的代码,但它根本没有做任何事情:

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 函数中的正则表达式用于根据上面的帖子确定发现卡。我注意到除了正则表达式中的“^”(即(“^4” - 签证,“^6001”发现))之外,我真的无法得到任何工作,但这显然在编辑的情况下是不够的示例。有什么想法吗?我认为这可能是我的 Java 的问题,但我正在运行 Java 7

我可能想提出一个新问题,但我也想知道即使用户返回并编辑数字(xxxx xxxx xxxx xxxx),如何使用正则表达式为各种信用卡获取正确的间距

编辑:从上面添加了调试日志。我的输入是一些应该与某些信用卡相关联的数字。目前我正在使用下面提供的 Eagle Eye 的代码(它也可以用于检测输入是一种卡片类型):

最终的 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

您可能希望日志“发现”会针对我输入的不同数字出现几次。上面的日志显示我输入了 Visa 卡和 Discover 卡的前几位数字。

发现编辑答案:我输入的数字不足,无法识别卡!

【问题讨论】:

您已链接到一个可以完全回答您问题各个方面的问题。 我的问题是为什么该代码对我不起作用。我认为问题出在 Java 或 android studio 发布您的日志。您要与该正则表达式匹配什么输入? (另外,您的代码仅测试 Discover 卡) 现在正确,我也单独测试了其他卡。我现在正在使用 EagleEye 的代码,它只是检查信用卡号是否与任何模式匹配,但日志仍然显示“发现” 【参考方案1】:

根据线程中的一个答案,可以根据以下数据验证卡片。

Visa:^4[0-9]6,$Visa 卡号以 4 开头。

万事达卡: ^5[1-5][0-9]5,$万事达卡号码以数字 51 到 55 开头,但这只会检测万事达卡信用卡;还有其他使用 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 开头。有些 Diners Club 卡以 5 开头,有 16 位数字。这些是 Diners Club 和万事达卡的合资企业,应该像万事达卡一样处理。

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;
      
   

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

Format credit card in edit text in android

编辑:

以卡号为16位为例,应用逻辑在4位后添加空格后,在处理实际卡号时需要将这些空格去掉。那么只有上面的逻辑才会起作用。

希望这会有所帮助。

【讨论】:

这对我不起作用。它从不进入 if 语句。 对不起,我的错。已更新答案。您需要删除卡号中添加的空格。 虽然您是对的,但不应该有空格,但我在没有空格的情况下输入了信用卡,但它仍然不起作用。某些正则表达式是否有可能在 Java 7 上不起作用? 如果我想检查属于哪个信用卡号,Visa 还是 master? Vilas 你能更新一下银联和铰链网络吗?【参考方案2】:

使用以下类来验证您的卡。

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' 的路径都没有被采用时,你会抛出一个异常,并且将它应用到其他情况。我也强烈反对缩写这个词。这个词是“算法”,来自一个专有名称。 这不是我想要做的,我试图弄清楚用户正在输入什么类型的信用卡,因为用户正在输入。我已经在实施一种验证算法来确定信用卡是否有效。 // VISA credit cards has length 13 - 15。没有。

以上是关于用于在 Android 中确定信用卡的正则表达式 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

用于验证日期的正则表达式 [重复]

使用尾随数字的正则表达式信用卡匹配

信用卡公司会发布官方正则表达式吗?

自动检测信用卡类型与询问用户

正则表达式

js 常用正则表达式表单验证代码