маскировка номера кредитной карты в 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 занимает больше времени, чем для цикла+StringBuffer в первой функции.Очевидно, что я использую api, неправильно..
кто-то может посоветуйте, как правильно использовать этот api, в данном случае?
10 ответов
во-первых, если вы делаете измерения такого короткого кода, Вы часто не получаете точных результатов из-за минимального разрешения синхронизации вашего CPU/library/whatever обеспечивает (что означает, что вы обычно получаете, чтобы увидеть 0ms или же небольшое значение снова и снова).
во-вторых, и что более важно, не оптимизировать этот! "преждевременная оптимизация-корень всех зол" и в случае, когда у вас есть только несколько МС, которые вы хотите оптимизировать усилия полностью впустую. Вам придется замаскировать миллионы кредитных карт, прежде чем вы даже отдаленно подумаете об оптимизации этого простого метода маски.
вот вы идете. Чистый и многоразовый:
/**
* 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
удачи.
вот немного более чистая реализация на основе 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);
}
Использование Apache StringUtils...
String ccNumber = "123232323767";
StringUtils.overlay(ccNumber, StringUtils.repeat("X", ccNumber.length()-4), 0, ccNumber.length()-4);
скорее всего, это время StringUtils
загружается из . Не настоящее время казни.
чтобы рассчитать Реальное время выполнения, попробуйте запустить несколько раз и посмотреть, сколько ms будет 2nd. 3-й до 100-й займет.
в любом случае, как сказал Фрэнк, оптимизация до этого уровня не рекомендуется.
строка utils, вероятно, копирует строку несколько раз. например, при запуске padded.concat (end); jvm выделяет новую строку размера двух строк concat и копирует их. Если вы используете StringBuffer, вы сохраняете все эти копии, так как буфер уже имеет место, и связанная строка просто скопирована там. для меня имеет смысл, что StringBuffer быстрее, хотя измеренное время кажется довольно большим, чем я ожидал.
хотя менее читаемый вы можете сделать это
final char[] ca = in.toCharArray();
Arrays.fill(ca, left, str.length - right, 'X');
return new String(ca)
использование суппорта Google на моей машине даст около 20-25 НС по сравнению с более чем 100ns с StringBuilder или StringUtils.наложение + повторение подходов.
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();
}
}
}
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]);
}
}
}
Я знаю, что это не ответ, но вы можете использовать регулярное выражение и решить это за один шаг
String replaced = originalCreditCardNo.replaceAll("\b(\d{4})(\d{8})(\d{4})", "XXXXXXXX");
объяснение:
- на \b граница помогает проверить, что мы в начале цифры (есть и другие способы сделать это, но здесь это будет делать).
- (\d{4}) захватывает четыре цифры в группу 1 и группу 3
- (\d{8}) захватывает восемь цифр в группу 2
- в замена, 1$ и 3$ содержат содержимое, сопоставленное группам 1 и 3
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);
}
out put: XXXXXXXXXXXX6785