他のプログラム言語とかでもよく出てくる「ゼロパディング」といわれる問題。
例えば5桁に揃えたい場合は、
「123」→「00123」
「AB」 →「000AB」
みたいな感じに加工する方法。
ゼロ埋め対象が数値変数の場合
data DT1; length V1 $5.; V0 = 123; V1 = put(V0, z5.); run; |
「Zw.dフォーマット」というのが用意されてて「z桁数」と指定するだけでok。
ゼロ埋め対象が文字変数の場合
data DT2; length V0 $3. V1-V3 $5.; V0 = "ABC"; V1 = reverse(substr(reverse(cats("00000",V0)),1,5)); * 方法① ; V2 = cats(repeat("0",4-lengthn(V0)),V0); * 方法② ; V3 = tranwrd(put(V0, 5.-R),' ','0'); * 方法③ ; run; |
だいたい上記3つのやり方が思い浮かぶ。
方法①
ごり押し感あるやり方。
「cats関数」で「00000ABC」という文字にする。
「reverse関数」で「CBA00000」と逆にしてから、
「substr関数」で先頭5文字を抽出「CBA00」
また「reverse関数」でもとの順に戻せば完成。
非効率だけどきらいじゃない。
追記
上記と同じ原理、かつもっといい方法を教えてもらいました。 V1 = put(put('00000'||V0 ,$revers8.),$revers5.); put関数にも文字を逆さまにする「$revers」というformatがある。 うまいのが「$revers5」で、5文字に切りつつ、もとの順に戻してるところ。 |
方法②
変数「V0」から不足してる文字の長さ分だけ「repeat関数」を使ってゼロを埋めてる。
方法③
個人的には使ってる関数も少なくて一番スマートだと思う。
数値変数の場合でも適用可。
その後、左側に出来た半角スペースを「tranwrd関数」でゼロに置換えてる。
「put関数」の「-R」については PUT関数の小技 を参照。
何回もコメントしてすみません。全然無視していただいて結構です。
返信削除面白い面白くないで言うならば、方法①が一番面白いです!そして一番好きです!
reverse関数を実用的に使用して、うまく活きている例を初めてみました。
いっぱいコメント貰えると嬉しいです!
返信削除方法①、いいですよね!
むかし実務でゼロ埋めする機会があって、
初めてやったのが①の方法なので、思い出深いです笑。
度々、すみません、方法①と似た考えで使用する関数の数を減らしたバージョンを
返信削除考えてみました。といっても、なんかこのやり方、どっかで見た気がするんで、パクリかも
しれません。
フォーマット名が長すぎて、すっきり感がでないので、やっぱり③ですかね
data DT2;
length V0 $3. V1_ $5.;
V0 = "ABC";
V1_=put(put('00000'||V0 ,$revers8.),$revers5.);
run;
これはうまい!
返信削除reverseがこんなに活かされてるの初めて見たかもしません。
非常にスマートなやり方です!
ありがとうございます!
欠損値のときと 先頭がスペース埋めのときなどに上手くいかなかったパターンがあったので、魔改造 + 新しい方法も考えてみました。
返信削除/* テストデータ */
data TEST ;
length V0 $5. ;
V0 = "A" ; output ;
V0 = "AB" ; output ;
V0 = "ABC" ; output ;
V0 = "ABCD" ; output ;
V0 = "ABCDE" ; output ;
V0 = "" ; output ; /* 欠損値 */
V0 = "12345" ; output ;
V0 = "1 3 5" ; output ; /* 間にスペースあり */
V0 = "12 45" ; output ; /* 間にスペースあり */
V0 = "1 3" ; output ; /* 間にスペースあり */
V0 = " 234" ; output ; /* 先頭にスペースあり */
run ;
data TEST ;
set TEST ;
length V2 V4 V5 $5. ;
/* 1. 先頭がスペースのとき、先頭スペースが残ったままにならないように、left関数を追加 */
/* 2. 欠損値のとき、ゼロが1つ少なかったので、cmiss関数を追加して対策 */
/* 3. ゼロ埋めするスペースがない = 5桁のとき、 */
/* repeat関数で、NOTE: ~引数が無効です。メッセージが出るので、 */
/* substr関数を追加し、repeat関数の 4 → 5 に変更 */
V2 = substr(cats(repeat("0", 5 - length(left(V0)) + cmiss(V0)), V0), 2, 5) ;
/* 1. 先頭がスペースのとき、先頭スペースが残ったままにならないように、left関数を追加 */
/* (catsでも可) */
/* 2. 入力文字が何桁でも対応できるように、$5. の2倍の値を設定 : $revers8. → $revers10. */
V4 = put(put('00000' || left(V0), $revers10.), $revers5.) ;
/* NEW ! */
V5 = substr(cats('00000', V0), length(left(V0)) - cmiss(V0) + 1, 5) ;
run ;
yoshinoさん、コメントありがとうございます!
削除そうか、欠損値の時はlength関数って「1」が返されちゃうんでしたね。
なので欠損値の時に、cmiss関数で「-1」して調整してるのか、、なるほどうまいですね!!
新しいアイディアも私の発想から抜けてたもので勉強になります。
ありがとうございます!