BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
Ronein
Meteorite | Level 14
Hello
I have data with last 4 digits of credit cards. I was asked to mask this data in a way that will change the value and i need to have the ability to convert it back from converted value to original value.
In the past i saw solution of mask customer id fueld using the following function
encode_X=put(X,$hex64.);
X=input(encode_X,$hex64.);
I saw that this function add "3"'s and it was perfect for my needs.
However now i was asked to convert it in other way ( not by adding '3"s) and keep have 4 digits.
May anyone suggest a way to do it ?
1 ACCEPTED SOLUTION

Accepted Solutions
Kurt_Bremser
Super User

Why so complicated?

data want;
set have;
do i = 1 to length(mezahe_part);
  if substr(mezahe_part,i,1) = "9"
  then substr(mezahe_part,i,1) = " ";
  else substr(mezahe_part,i,1) = put(sum(1,input(substr(mezahe_part,i,1),1.)),1.);
end;
drop i;
run;

To decode, turn blanks into a 9, zeroes into blanks, otherwise subtract 1.

View solution in original post

14 REPLIES 14
PeterClemmensen
Tourmaline | Level 20

Why not create a format to mask the last 4 digits without actually changing the underlying value?

Ronein
Meteorite | Level 14

May you please show code?

Please note that I need to export the data set into txt file  and in the txt file need to see the masked value.

Patrick
Opal | Level 21

And none of the answers in your previous question here give you already solution approaches?

ballardw
Super User

Are your values numeric or character?

How about providing some examples of what the value currently look like?

Any rules/limits about what the "change" is allowed to do?

Ronein
Meteorite | Level 14

I thought about code like that.

Here is the code that is working well, I add 1 to each digit.

Any other shorter suggestions?

 


Data have;
input  MEZAHE_PART;
cards;
9
710
1040
1323
1417
1610
1618
1922
2143
2323
2413
2511
2629
2823
3026
3218
3711
3720
3928
4213
4219
4223
4318
4811
5283
5428
6315
6320
6412
6610
6726
6727
6915
6919
7125
7222
7514
7620
7958
8119
8213
8420
9327
9721
9726
9827
;
Run;

Data want;
set have;
IF substr(cat(MEZAHE_PART),1,1) ne '' then D1=substr(cat(MEZAHE_PART),1,1);else D1='';
IF substr(cat(MEZAHE_PART),2,1) ne '' then D2=substr(cat(MEZAHE_PART),2,1);else D2='';
IF substr(cat(MEZAHE_PART),3,1) ne '' then D3=substr(cat(MEZAHE_PART),3,1);else D3='';
IF substr(cat(MEZAHE_PART),4,1) ne '' then D4=substr(cat(MEZAHE_PART),4,1);else D4='';

D1_b=put(D1,$Mask_Fmt.);
D2_b=put(D2,$Mask_Fmt.);
D3_b=put(D3,$Mask_Fmt.);
D4_b=put(D4,$Mask_Fmt.);
Masked_MEZAHE_PART=CATS(D1_b,D2_b,D3_b,D4_b);

IF substr(cat(Masked_MEZAHE_PART),1,1) ne '' then D1_c=substr(cat(Masked_MEZAHE_PART),1,1);else D1_c='';
IF substr(cat(Masked_MEZAHE_PART),2,1) ne '' then D2_c=substr(cat(Masked_MEZAHE_PART),2,1);else D2_c='';
IF substr(cat(Masked_MEZAHE_PART),3,1) ne '' then D3_c=substr(cat(Masked_MEZAHE_PART),3,1);else D3_c='';
IF substr(cat(Masked_MEZAHE_PART),4,1) ne '' then D4_c=substr(cat(Masked_MEZAHE_PART),4,1);else D4_c='';

D1_d=put(D1_c,$Converted_Back_Mask_Fmt.);
D2_d=put(D2_c,$Converted_Back_Mask_Fmt.);
D3_d=put(D3_c,$Converted_Back_Mask_Fmt.);
D4_d=put(D4_c,$Converted_Back_Mask_Fmt.);
_MEZAHE_PART_=CATS(D1_d,D2_d,D3_d,D4_d);
Drop  D1  D2 D3 D4  D1_b  D2_b  D3_b D4_b D1_c  D2_c  D3_c  D4_c D1_d D2_d D3_d D4_d;
Run;
Patrick
Opal | Level 21

Using your sample data below one way to go.

data want;
  if _n_=1 then
    do;
      if 0 then masked_value=MEZAHE_PART;
      format masked_value z4.;
      dcl hash h1();
      h1.defineKey('MEZAHE_PART');
      h1.defineData('masked_value');
      h1.defineDone();
    end;
  set have;
  if h1.find() ne 0 then
    do;
      masked_value=h1.num_items;
      if masked_value=MEZAHE_PART then
        do;
          masked_value=9999-h1.num_items;
        end;
      _rc=h1.add();
    end;
  drop _rc MEZAHE_PART;
run;

An enhanced code sample already shared in your other question referenced earlier.

Ronein
Meteorite | Level 14
Can you please show the code how to convert back masked_value into MEZAHE_PART? I want to see that I get the original values. Can you also explain the mask way that you applied? what is the secret mask formula applied?
Kurt_Bremser
Super User

Why so complicated?

data want;
set have;
do i = 1 to length(mezahe_part);
  if substr(mezahe_part,i,1) = "9"
  then substr(mezahe_part,i,1) = " ";
  else substr(mezahe_part,i,1) = put(sum(1,input(substr(mezahe_part,i,1),1.)),1.);
end;
drop i;
run;

To decode, turn blanks into a 9, zeroes into blanks, otherwise subtract 1.

Ronein
Meteorite | Level 14

Thanks,

As I see in your code you run  on each digit and perform calculation to get the new digit value.

I have 2 questions please regarding your code:

1- Where in the code you tell SAS to concatenate the digits?

2- Where in the code you tell the name of the new column (I see that the name is  mezahe_part)?

data want;
set have;
Before_mask=mezahe_part;
do i = 1 to length(mezahe_part);
if substr(mezahe_part,i,1) = "9" then substr(mezahe_part,i,1) = " ";
else substr(mezahe_part,i,1) = put(sum(1,input(substr(mezahe_part,i,1),1.)),1.);
end;
drop i;
run;
ballardw
Super User

Just lovely. A question that asks about "masking" the LAST 4 digits and then the first two examples of values do not have 4 digits and one only has one digit.

 

So, do you need to add some more details to the requirements?

 

Values like credit card account numbers or "last 4 of credit card account" really should not be numeric.

I really bet the last 4 digits of the account are not "9". Possibly "0009".  And then attempt to process a numeric value with string functions and don't even attempt to control how the string is created from the numeric values.

Just how many "numeric values have been converted to character" notes appear in the log?

 


@Ronein wrote:

I thought about code like that.

Here is the code that is working well, I add 1 to each digit.

Any other shorter suggestions?

 


Data have;
input  MEZAHE_PART;
cards;
9
710
1040
1323
1417
1610
1618
1922
2143
2323
2413
2511
2629
2823
3026
3218
3711
3720
3928
4213
4219
4223
4318
4811
5283
5428
6315
6320
6412
6610
6726
6727
6915
6919
7125
7222
7514
7620
7958
8119
8213
8420
9327
9721
9726
9827
;
Run;

 

 

Ronein
Meteorite | Level 14
You are absolutely right. The description of field is "last 4 digits" however the field is numeric and i found cases when have less than 4 digits and this is the reason that i added it to the data aet
SASKiwi
PROC Star

@Ronein  - You can't store 16 digit credit card numbers accurately in SAS numeric variables because of precision limitations. I just hope you aren't doing this because you will end up with "random" digit changes in the last one or two digits. I deal with credit card numbers all the time and have frequently seen this problem.

Ksharp
Super User

Data have;
input  MEZAHE_PART;
cards;
9
710
1040
1323
1417
1610
1618
1922
2143
2323
2413
2511
2629
2823
3026
3218
3711
3720
3928
4213
4219
4223
4318
4811
5283
5428
6315
6320
6412
6610
6726
6727
6915
6919
7125
7222
7514
7620
7958
8119
8213
8420
9327
9721
9726
9827
;
Run;
data want;
 set have;
 length encode $ 20;
 temp=put(MEZAHE_PART,best8. -l);
 do i=1 to lengthn(temp);
   encode=cats(encode,byte(rank(  ifc(char(temp,i)='9','/',char(temp,i))  ) + 1));
 end;
 drop temp i;
run;
data want;
 set want;
 length decode $ 20;
 do i=1 to lengthn(encode);
   decode=cats(decode,byte(rank(  ifc(char(encode,i)='0',':',char(encode,i))  ) - 1));
 end;
 drop i;
run;

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 14 replies
  • 832 views
  • 5 likes
  • 7 in conversation