- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I have set of rules to be applied to individual characters
data have;
input str $34.;
cards;
my name is john
;
run;
Below is translation rule
Letter | translation |
m | 12 |
y | 45 |
n | 89 |
a | 22 |
e | 87 |
i | 90 |
s | 24 |
j | 88 |
o | 64 |
h | 32 |
n | 8 |
Hence my output should look like this
124589221287902488643258
I tried using translate and tranwrd , but somehow could not get individual letters replacement correct.
Any help is really appreciated
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
You could code and decode your strings using a pseudo-random translation table, based on a (secret) seed. You would need 3 numeric characters in your scrambled string for each character in your original string.
data have;
input str $34.;
cards;
my name is john
;
/* Set the key to the random permutation */
%let key = 8765764;
data want;
array v {0:255} $3 _temporary_;
if _n_ = 1 then do;
seed = &key.;
do i = 0 to 255;
v{i} = put(i, z3.);
end;
call ranperm(seed, of v{*});
end;
length newStr $300;
set have;
call missing(newStr);
do i = 1 to length(str);
substr(newStr, 3*i-2, 3) = v{rank(char(str, i))};
end;
drop i seed;
run;
/* Now translate the string back, using the same key, i.e. the same random translation table */
data decode;
array v {0:255} _temporary_;
array x {0:255} _temporary_;
if _n_ = 1 then do;
seed = &key.;
do i = 0 to 255;
x{i} = i;
end;
call ranperm(seed, of x{*});
/* Reverse the translate table */
do i = 0 to 255;
v{x{i}} = i;
end;
end;
set want;
length recStr $100;
call missing(recStr);
do i = 1 to length(newStr)/3;
substr(recStr, i, 1) = byte(v{input(substr(newStr, 3*i-2, 3), 3.)});
end;
drop i seed;
run;
proc print data=decode noobs; run;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Do you want to change 'n' into '89' or '8'?
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
You could use temporary arrays with the CHAR and RANK functions
data have;
input str $34.;
cards;
my name is john
;
data want;
array v {0:27} $3 _temporary_
(" " /*
a b c d e f g h i j */
"22" " " " " " " "87" " " " " "32" "90" "88" /*
k l m n o p q r s t */
" " " " "12" "89" "64" " " " " " " "24" " " /*
u v w x y z */
" " " " " " " " "45" " "
"**");
array str2 {99} $3 _temporary_;
set have;
length newStr $200;
call missing(of str2{*});
do i = 1 to length(str);
str2{i} = v{max( min( rank(char(str, i)) - rank("a") + 1, 27), 0)};
end;
newStr = cats(of str2{*});
drop i;
run;
proc print data=want noobs; run;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Where did the space between the words go? You did not specify any rule on handling them but they do not appear in the output.
Translate will not work because that translates one character to one character. So "m" to "12" would be one character to 2.
You also have a problem with either Translate or Tranwrd because you want to map the letter n to two different values and neither of the functions are going to like that because the First n that gets changed to 89 will change both and there won't be one to have just 8.
And last, there is nothing in your list creates a 5 in the next to last position. You say the result should be
124589221287902488643258
The 32 just before that comes from the highlighted 5 from the h. If the final n is supposed to become 8, then where did that 5 come from???????
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi @Swapnil_21,
The problem of translating one letter into two digits with TRANSLATE can be overcome by means of hexadecimal digits:
data want;
set have;
result=put(translate(compress(str),'12458922879024886432'x,'mynaeisjoh'),$hex68.);
run;
(assuming that the two inconsistencies the others have mentioned are just typos).
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Looks like I messed up while giving the input . Let me simplify it.
Input : War started
Output: 12345623689
W>1,a->2,r->3,space->4,s->5,t->6,a->2,r->3,t->6,e->8,d->9
Kindly suggest. If any other approaches then that also suggest. My objective is just to mask the data and i should be able to unmask it later
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Unmasking is only possible if each char is replaced by the same number of digits. Depending on the chars you expect, using two digits may or may not be sufficient.
I would define a format as translation table and use a loop for translation. Without the need to unmask the values later, you could use function sha256, the docs have details: https://documentation.sas.com/doc/de/pgmsascdc/9.4_3.4/lefunctionsref/p04sqiymw1a6unn1uvh943eudcvz.h...
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi @Swapnil_21
If you just want to mask the string, you could translate it to octagonal representation. The resulting string is printable and contains only digits 0-7.
Everybody could unmask the string if they figure out that it is actually octagonal, so it is not a real encryption with a key, but who would think of octagonal codes in 2022?
And it is a very simple operation i SAS:
data a;
text = 'my name is john';
text_masked = put(text,$octal200.);
text_restored = input(text_masked,$octal200.);
put text / text_masked / text_restored;
run;
my name is john
155171040156141155145040151163040152157150156
my name is john
turn the string and still have it as a string of printable caharactersby turning it as a string of digits, so it
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
You could code and decode your strings using a pseudo-random translation table, based on a (secret) seed. You would need 3 numeric characters in your scrambled string for each character in your original string.
data have;
input str $34.;
cards;
my name is john
;
/* Set the key to the random permutation */
%let key = 8765764;
data want;
array v {0:255} $3 _temporary_;
if _n_ = 1 then do;
seed = &key.;
do i = 0 to 255;
v{i} = put(i, z3.);
end;
call ranperm(seed, of v{*});
end;
length newStr $300;
set have;
call missing(newStr);
do i = 1 to length(str);
substr(newStr, 3*i-2, 3) = v{rank(char(str, i))};
end;
drop i seed;
run;
/* Now translate the string back, using the same key, i.e. the same random translation table */
data decode;
array v {0:255} _temporary_;
array x {0:255} _temporary_;
if _n_ = 1 then do;
seed = &key.;
do i = 0 to 255;
x{i} = i;
end;
call ranperm(seed, of x{*});
/* Reverse the translate table */
do i = 0 to 255;
v{x{i}} = i;
end;
end;
set want;
length recStr $100;
call missing(recStr);
do i = 1 to length(newStr)/3;
substr(recStr, i, 1) = byte(v{input(substr(newStr, 3*i-2, 3), 3.)});
end;
drop i seed;
run;
proc print data=decode noobs; run;