it-swarm.com.ru

маскировка номера кредитной карты в java

Я попытался замаскировать символы в строке номера кредитной карты, используя символ "X". Я написал две функции, как показано ниже. Вторая функция использует класс commons.lang.StringUtils. Я пытался найти время, которое требуется в обоих случаях

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 в этом случае?

7
jimgardener

Во-первых, если вы выполняете измерения такого короткого кода, вы часто не получаете точных результатов из-за минимального временного разрешения, которое ваш ЦП/библиотека/что-либо обеспечивает (что означает, что вы обычно получаете 0 мс или одно и то же небольшое значение снова и снова). над).

Во-вторых, что еще более важно, не оптимизируйте это! "Преждевременная оптимизация - корень всего зла" и в случае, если у вас есть всего несколько мс, которые вы хотите оптимизировать, усилия полностью напрасны. Вам придется замаскировать миллионы кредитных карт, прежде чем вы хотя бы отдаленно подумаете об оптимизации этого простого метода маски.

5
Frank

Ну вот. Чистый и многоразовый:

/**
 * 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

Удачи.

16
Ayman

Вот немного более чистая реализация, основанная на 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);
}
7
Michael-7

Используя Apache StringUtils ...

String ccNumber = "123232323767"; 

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

Скорее всего, это время загрузки StringUtils из файла Apache-commons.jar. Не настоящее время выполнения.

Чтобы вычислить реальное время выполнения, попробуйте запустить несколько раз и посмотрите, сколько мс будет 2-го числа. 3-го до 100-го займет.

В любом случае, как сказал Фрэнк, оптимизация до этого уровня не рекомендуется.

2
medopal

String Utils, вероятно, копирует строку несколько раз. например, когда вы запускаете padded.concat (end); jvm выделяет новую строку размером двух строк concat и копирует их. Если вы используете StringBuffer, вы сохраняете все эти копии, так как в буфере уже выделено место и только что скопированная строка скопирована туда. Мне кажется, что StringBuffer быстрее, хотя измеренное время кажется довольно большим, чем я ожидал.

2
roni
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]);
        }
    }
}
2
abhinav kumar

Хотя это менее читабельно, вы можете сделать это

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

Использование Google Caliper на моей машине даст около 20-25 нс по сравнению с более чем 100 нс с подходами StringBuilder или StringUtils.overlay + repeat.

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();
        }
    }
}
1
Archimedes Trajano

Я знаю, что это не ответ, но вы можете использовать регулярное выражение и решить это за один шаг

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

Объяснение:

  • Граница \ b помогает проверить, что мы являемся началом цифр (есть другие способы сделать это, но здесь это будет сделано).
  • (\ d {4}) фиксирует четыре цифры для группы 1 и группы 3
  • (\ d {8}) фиксирует восемь цифр для группы 2
  • В заменах $ 1 и $ содержат контент, соответствующий группам 1 и 3
1
padippist

Ниже код замаскирует 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;
}
0
Tint Naing Win