在java中屏蔽信用卡号

时间:2011-09-20 05:39:45

标签: java masking apache-commons-lang

我试图使用字符'X'来掩盖信用卡号码字符串中的字符。我写了两个函数如下。第二个函数使用commons.lang.StringUtils类。我试图找到两种情况下的时间< / p>

public static String maskCCNumber(String ccnum){
        long starttime = System.currentTimeMillis();
        int total = ccnum.length();
        int startlen=4,endlen = 4;
        int masklen = total-(startlen + endlen) ;
        StringBuffer maskedbuf = new StringBuffer(ccnum.substring(0,startlen));
        for(int i=0;i<masklen;i++) {
            maskedbuf.append('X');
        }
        maskedbuf.append(ccnum.substring(startlen+masklen, total));
        String masked = maskedbuf.toString();
        long endtime = System.currentTimeMillis();
        System.out.println("maskCCNumber:="+masked+" of :"+masked.length()+" size");
        System.out.println("using StringBuffer="+ (endtime-starttime)+" millis");
        return masked;
    }

    public static String maskCCNumberCommons(String ccnum){
        long starttime = System.currentTimeMillis();
        int total = ccnum.length();
        int startlen=4,endlen = 4;
        int masklen = total-(startlen + endlen) ;
        String start = ccnum.substring(0,startlen);
        String end = ccnum.substring(startlen+masklen, total);
        String padded = StringUtils.rightPad(start, startlen+masklen,'X'); 
        String masked = padded.concat(end);
        long endtime = System.currentTimeMillis();
        System.out.println("maskCCNumber:="+masked+" of :"+masked.length()+" size");
        System.out.println("using Stringutils="+(endtime-starttime)+" millis");
        return masked;
    }

public static void ccNumberMaskingDemo() {
   String mcard1="5555555555554444";
   maskCCNumber(mcard1);
   maskCCNumberCommons(mcard1);
}

当我跑这个时,我得到了这个结果

maskCCNumber:=5555XXXXXXXX4444 of :16 size
using StringBuffer=0 millis
maskCCNumber:=5555XXXXXXXX4444 of :16 size
using Stringutils=25 millis

我无法理解为什么commons.StringUtils比第一个函数中的for循环+ StringBuffer花费的时间更多。显然我正在使用api,错误的方式..

在这种情况下,有人可以建议如何正确使用此API吗?

11 个答案:

答案 0 :(得分:16)

你走了。清洁和可重复使用:

/**
 * Applies the specified mask to the card number.
 *
 * @param cardNumber The card number in plain format
 * @param mask The number mask pattern. Use # to include a digit from the
 * card number at that position, use x to skip the digit at that position
 *
 * @return The masked card number
 */
public static String maskCardNumber(String cardNumber, String mask) {

    // format the number
    int index = 0;
    StringBuilder maskedNumber = new StringBuilder();
    for (int i = 0; i < mask.length(); i++) {
        char c = mask.charAt(i);
        if (c == '#') {
            maskedNumber.append(cardNumber.charAt(index));
            index++;
        } else if (c == 'x') {
            maskedNumber.append(c);
            index++;
        } else {
            maskedNumber.append(c);
        }
    }

    // return the masked number
    return maskedNumber.toString();
}

示例通话:

System.out.println(maskCardNumber("1234123412341234", "xxxx-xxxx-xxxx-####"));
> xxxx-xxxx-xxxx-1234

System.out.println(maskCardNumber("1234123412341234", "##xx-xxxx-xxxx-xx##"));
> 12xx-xxxx-xxxx-xx34
祝你好运。

答案 1 :(得分:8)

这是一个基于StringUtils的略微更清晰的实现,但我不确定它与你的实现相比会如何表现。无论如何,“过早优化”评论仍然非常有效。

    public static String maskNumber(final String creditCardNumber) {
    final String s = creditCardNumber.replaceAll("\\D", "");

    final int start = 4;
    final int end = s.length() - 4;
    final String overlay = StringUtils.repeat(MASK_CHAR, end - start);

    return StringUtils.overlay(s, overlay, start, end);
}

答案 2 :(得分:7)

使用Apache StringUtils ......

String ccNumber = "123232323767"; 

StringUtils.overlay(ccNumber, StringUtils.repeat("X", ccNumber.length()-4), 0, ccNumber.length()-4);

答案 3 :(得分:5)

首先,如果你对这种短时间运行的代码进行测量,由于你的CPU /库/提供的最小时序分辨率,你经常得不到准确的结果(这意味着你通常会看到0ms或相同的小价值一遍又一遍。)

其次,更重要的是,不要优化这个! “过早优化是所有邪恶的根源”,如果你只有几毫秒,你想要优化努力就彻底浪费了。在你甚至应该远程考虑优化这种简单的掩模方法之前,你必须屏蔽数百万张信用卡。

答案 4 :(得分:2)

最有可能的是,这是从StringUtils文件加载apache-commons.jar的时间。不是真正的执行时间。

要计算实际执行时间,请尝试多次运行并查看第二个多少ms。第3到第100将采取。

无论如何,正如弗兰克所说,不建议优化到这个水平。

答案 5 :(得分:2)

String utils可能会复制字符串几次。例如,当你运行padded.concat(结束); jvm分配两个concat字符串大小的新字符串并复制它们。如果使用StringBuffer,则保存所有这些副本,因为缓冲区已经分配了位置,并且在那里复制了连接的字符串。让我觉得StringBuffer更快,虽然测量的时间看起来比我想象的要大。

答案 6 :(得分:2)

import java.util.Scanner;
class StringTest{
    public static void main(String ar[]){
        Scanner s=new Scanner(System.in);

        System.out.println("enter account number");
        String name=s.next();
        char a[]=new char[name.length()];
        for(int i=0;i<name.length();i++){
            a[i]=name.charAt(i);
        }
        for(int i=1;i<name.length()-3;i++){
            a[i]='*';
        }

        System.out.println("your account number");
        for(int i=0;i<name.length();i++){
            System.out.print(a[i]);
        }
    }
}

答案 7 :(得分:1)

虽然可读性较差,但您可以这样做

final char[] ca = in.toCharArray();
Arrays.fill(ca, left, str.length - right, 'X');
return new String(ca)

在我的机器上使用Google Caliper会产生大约20-25 ns,而使用StringBuilder或StringUtils.overlay + repeat方法则超过100ns。

import static org.apache.commons.lang3.StringUtils.overlay;
import static org.apache.commons.lang3.StringUtils.repeat;

import java.util.Arrays;

import org.apache.commons.lang3.StringUtils;

import com.google.caliper.Param;
import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;

public class ArrayCopyVsStringBuild extends SimpleBenchmark {

    public static void main(final String[] args) throws Exception {
        Runner.main(ArrayCopyVsStringBuild.class, args);
    }

    @Param({ "1234567890123456", "1234567890" })
    private String input;

    @Param({ "0", "4" })
    private int left;

    @Param({ "0", "4" })
    private int right;

    public void timeArray(final int reps) {
        for (int i = 0; i < reps; i++) {
            final char[] masked = input.toCharArray();
            Arrays.fill(masked, left, masked.length - right, 'X');
            final String x = new String(masked);
            x.toString();
        }
    }

    public void timeStringBuilder(final int reps) {
        for (int i = 0; i < reps; i++) {
            final StringBuilder b = new StringBuilder(input.length());
            b.append(input.substring(0, left));
            for (int z = 0; z < input.length() - left - right; ++z) {
                b.append('X');
            }
            b.append(input.substring(input.length() - right));
            final String x = b.toString();
            x.toString();
        }
    }

    public void timeStringUtils(final int reps) {
        for (int i = 0; i < reps; i++) {
            final StringBuilder b = new StringBuilder(input.length());
            b.append(input.substring(0, left));
            b.append(repeat('x', input.length() - left - right));
            b.append(input.substring(input.length() - right));
            final String x = b.toString();
            x.toString();
        }
    }

    public void timeStringUtilsOverlay(final int reps) {
        for (int i = 0; i < reps; i++) {
            final int maskLength = input.length() - left - right;
            final String x = overlay(input, repeat('x', maskLength), left,
                    maskLength + left);
            x.toString();
        }
    }
}

答案 8 :(得分:1)

我知道这不是答案,但你可以使用正则表达式并一步解决这个问题

String replaced = originalCreditCardNo.replaceAll("\\b(\\d{4})(\\d{8})(\\d{4})", "$1XXXXXXXX$3");

说明:

  • \ b 边界有助于检查我们是否为数字的开头(还有其他方法可以执行此操作,但此处可以这样做。)
  • (\ d {4})将4位数字捕获到第1组和第3组
  • (\ d {8})将8位数字捕获到第2组
  • 在替换中, $ 1 $ 3 包含与第1组和第3组匹配的内容

答案 9 :(得分:0)

下面的代码将屏蔽字符串的75%。

public static String mask(String input) {

    int length = input.length() - input.length()/4;
    String s = input.substring(0, length);
    String res = s.replaceAll("[A-Za-z0-9]", "X") + input.substring(length);


    return res;
}

答案 10 :(得分:-1)

String existingCCNmbr = "4114360123456785";
    int i = 0;
    StringBuffer temp = new StringBuffer();
    while(i < (existingCCNmbr .length())){
        if(i > existingCCNmbr .length() -5){
            temp.append(existingCCNmbr.charAt(i));
        } else {
            temp.append("X");
        }
        i++;
    }
       System.out.println(temp);
       }

输出:XXXXXXXXXXXX6785