BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Swapnil_21
Obsidian | Level 7

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

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
PGStats
Opal | Level 21

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;

PGStats_0-1645909428116.png

 

PG

View solution in original post

8 REPLIES 8
Tom
Super User Tom
Super User

Do you want to change 'n' into '89' or '8'?

PGStats
Opal | Level 21

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;

PGStats_0-1645476430485.png

 

PG
ballardw
Super User

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???????

FreelanceReinh
Jade | Level 19

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).

Swapnil_21
Obsidian | Level 7

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 

 

 

andreas_lds
Jade | Level 19

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...

ErikLund_Jensen
Rhodochrosite | Level 12

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 

 

 

PGStats
Opal | Level 21

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;

PGStats_0-1645909428116.png

 

PG

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
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
  • 8 replies
  • 1486 views
  • 5 likes
  • 7 in conversation