SASマクロ データ変換

【SAS】ユニークコード(パスワード)を生成するマクロ(ハッシュオブジェクト)

unique_data_indata

1.既存のデータセットに付与するパターン

1.サンプルデータ

サンプルとして、事前に、以下のようなデータセットを用意します。

data hojin_list;
	infile datalines dlm="," dsd missover;
	input hojin_name:$200.;
datalines;
日本郵船株式会社
株式会社Mizkan J plus Holdings
公益社団法人福岡医療団
社団医療法人 啓愛会
一般社団法人 北陸地区信用金庫協会
兵庫県弁護士協同組合
学校法人 藤田学園
一般財団法人東北電気保安協会
社会医療法人蘇西厚生会
公益社団法人福岡医療団
田中貴金属労働組合
医療法人社団 友愛病院会
東京海上日動調査サービス共済組合
社会医療法人財団白十字会
オカムラグループ健康保険組合
日本ヒューレット・パッカード合同会社
社団医療法人 啓愛会
;
run;

データセットを開くと以下のようになります。
hojin
 

2.展開例

以下の展開例は、生成するパスワードに含めたくない文字列をマクロexceptとして指定しています。
引数exceptは省略可能なので、マクロexceptは無くても問題ないです。

%macro except;
/*--------------------------------------------------
exceptに指定した文字列を含むPASSWORDは生成されない
※大文字・小文字の区別は無視する
--------------------------------------------------*/
g9h43NmTb5
Nt7tyb8Ae6
YRmY73dgEF
%mend except;

%mk_unique_code(
	indata		=hojin_list, 
	obs		    =,
	pw_vname	=pw,
	pw_length	=10,
	seed		=12345, 
	moji		=ABDEFGHJLMNQRTYabdefghjmnrty23456789,
	yomi		=%yomi,
	except		=%except,
	outdata		=unique_data
);

 

3.出力結果

以下のように、入力データセットに対し、パスワードが付与されています。
unique_data_indata

 

2.任意のOBS数で生成するパターン

1.展開例

既存のデータセットに付与せず、任意のOBS数でパスワードを生成したい場合は、以下のように引数obsにオブザベーション数を指定します。

%mk_unique_code(
	indata		=, 
	obs		    =1000,
	pw_vname	=pw,
	pw_length	=10,
	seed		=12345, 
	moji		=ABDEFGHJLMNQRTYabdefghjmnrty23456789,
	yomi		=%yomi,
	except		=,
	outdata		=unique_data
);

 

2.出力結果

以下のように、1000オブザベーションのデータセットが生成されます。
unique_data_1000
 

3. 参考プログラム

以下は、参考プログラムになります。
右上のコピーボタンを押せば、プログラム全体をコピーできます。

%macro mk_unique_code(indata=, obs=, pw_vname=, pw_length=, seed=, moji=, yomi=, except=, outdata=);
%put --------------------------------------------------;
%put ユニークコードの生成;
%put &=indata;		/*ユニークコードを付与するSASデータセット名を指定する(省略する場合は、obsの指定必須)*/
%put &=obs;		    /*indataを省略する場合にのみ生成OBS数を指定する(indataに指定した場合は機能しない)*/
%put &=pw_vname;	/*PASSWORDを格納する変数名を指定*/
%put &=pw_length;	/*PASSWORDの文字長さを指定*/
%put &=seed;		/*RAND関数のSEED値を指定*/
%put &=moji;		/*PASSWORDに使用する半角英数字を指定*/
%put &=yomi;		/*PASSWORDに読み仮名を付与する場合は指定する(省略可)*/
%put &=except;		/*exceptに指定した文字列を含むPASSWORDは生成されない(省略可)*/
%put &=outdata;		/*出力するSASデータセット名を指定*/
%put --------------------------------------------------;

	%put ----- OBS数のマクロ変数化 -----;
	%if %length(&indata.)>0 %then %do;
		data _mk_unique_code_data;
			set &indata.;
		run;
		proc sql noprint;
			select count(*) into:__obs from _mk_unique_code_data;
		quit;
	%end;
	%else %do;
		%let __obs=&obs.;
	%end;

	%put ----- ユニークコード&pw_vname.の生成 -----;
	data _mk_unique_code_id;

		drop __:;
		length &pw_vname. $&pw_length..;

		if _N_ = 1 then do;
	  		declare hash h1();

	  		h1.definekey("&pw_vname.");
	  		h1.definedone();
 		end;

		__n=length("&moji.");
		__kumi=__n**&pw_length.;

		put "NOTE:与えられた文字数 = " __n;
		put "NOTE:生成できる組み合わせ数 = " __kumi;

		call streaminit(&seed.);

		do until(__obs=&__obs.);
			do until(__okflg=1);
				do __i = 1 to &pw_length.;

					__r=int(rand("uniform") * length("&moji.") +1);
    				&pw_vname. = cats(&pw_vname. , char("&moji.", __r));

					__e = 1;
					__e_cnt=0;
					do while(not missing(scan("&except.", __e,, "s")));
						if find(&pw_vname., scan("&except.", __e,, "s"), "i") > 0 then __e_cnt + 1;
						__e + 1;
					end;

    				if __i = &pw_length. then do;
						if h1.check() ne 0 and __e_cnt = 0 then do;
							__okflg=1;
							h1.add();
	      					output;
							__obs+1;
	      					
	     				end;
	     				else &pw_vname.="";
					end;
   				end;
  			end;
 		end;
	run;

	%if %length(%superq(yomi)) > 0 %then %do;
		%put ----- 読みの追加 -----;
		data _mk_unique_code_id;
			set _mk_unique_code_id;
			length &pw_vname._yomi $32767.;

			&pw_vname._yomi=&pw_vname.;

			%let _i=1;
			%do %while(%qscan(%superq(yomi), &_i.,,s) ne);
				&pw_vname._yomi=tranwrd(&pw_vname._yomi, scan("%qscan(%superq(yomi), &_i.,,s)",1,"|"), "・"||scan("%qscan(%superq(yomi), &_i.,,s)",2,"|"));
				if substr(&pw_vname._yomi,1,1)="・" then &pw_vname._yomi=substr(&pw_vname._yomi,2);
				%let _i=%eval(&_i.+1);
			%end;
		run;
	%end;

	
	%if %length(&indata.)>0 %then %do;
		%put ----- 入力データセットにマージして出力 -----;
		data &outdata.;
			merge
				_mk_unique_code_data
				_mk_unique_code_id
			;
			if missing(&pw_vname.) then put "ERROR:正しくユニークコードが生成されていません" +2 (&pw_vname.)(=);
		run;
	%end;
	%else %do;
		%put ----- 出力 -----;
		data &outdata.;
			set _mk_unique_code_id;
			if missing(&pw_vname.) then put "ERROR:正しくユニークコードが生成されていません" +2 (&pw_vname.)(=);
		run;
	%end;

	%put ----- 不要データセットの削除 -----;
	proc datasets lib=work noprint;
		delete _mk_unique_code_:;
	quit;

%mend mk_unique_code;


%macro yomi;
/*--------------------------------------------------
半角英数字の読み
--------------------------------------------------*/
A|エー
B|ビー
D|ディー
E|イー
F|エフ
G|ジー
H|エイチ
J|ジェイ
L|エル
M|エム
N|エヌ
Q|キュー
R|アール
T|ティー
Y|ワイ
2|ニ
3|サン
4|ヨン
5|ゴ
6|ロク
7|ナナ
8|ハチ
9|キュウ
A|エー
B|ビー
D|ディー
E|イー
F|エフ
G|ジー
H|エイチ
J|ジェイ
L|エル
M|エム
N|エヌ
Q|キュー
R|アール
T|ティー
Y|ワイ
a|エー
b|ビー
d|ディー
e|イー
f|エフ
g|ジー
h|エイチ
j|ジェイ
m|エム
n|エヌ
r|アール
t|ティー
y|ワイ
2|ニ
3|サン
4|ヨン
5|ゴ
6|ロク
7|ナナ
8|ハチ
9|キュウ
%mend yomi;