2025年4月1日火曜日

複数の変数に同じ処理をかける時は配列が使えるの話

 例えばA、B、Cの3つの変数に同じ処理…今回はそれぞれに+1する…を実行する時、arrayが使えることもある。同じ処理をピコピコと繰り返し書くのが面倒な時は配列に記載してやればいっぱい似たようなものを書かなくて良い。具体例は以下の通り。

配列hogeを定義して、do overで全部にdo以下の処理を当てはめている。dimで要素数取って、とかをやっても良いのだが、今の場合のように全部に処理をすることが明らかな場合はわざわざdimで要素数を取らなくても良い。

data _null_ ;

    a = 1 ;

    b = 2 ;

    c = 3 ;

    array hoge a b c ;

    do over hoge ;

        hoge = hoge + 1 ;

    end ;

    putlog a b c ;

run ;

2025年3月1日土曜日

rtfの表に上付きの🄬を出力する

rtfの表内に上付き文字を出したいときはインラインフォーマットで^{super A}とすると上付き文字のAが出せますし、ギリシャ文字なんかを出すときは^{unicode 03B2}で出したりします。

環境依存文字の🄬も似たように^{unicode 24C7}でrtf上に出せますが、上付きの🄬…ユニコード指定の文字を上付き…で出すには工夫が要るのか…?という話です。特段の工夫とかは要らず、hoge^{super ^{unicode 24C7}}とやるとhogeの右肩に🄬を出すことができます。便利ですね。


インラインフォーマット指定前の^はods escapecharacterで指定しています。試してないのですが、defaultの(*esc*)だと重ねれない気がするので何かしらの文字をエスケープ文字として設定してください 

2025年2月7日金曜日

最新の更新日時のフォルダ/ファイルを取得する

指定したフォルダの中から最も新しいファイル(例えばxlsxなりcsv…) のファイル名を取得したい時があります。ファイル名が同じで中身だけ更新されるならプログラムを変えなくても良いですが、更新のたびにな前の末尾に日付が入ったりしてファイル名が更新される時があります。そんな時に毎度プログラムを更新するのはちょっとめんどくさいので、更新日時が一番最後のファイルの名前をマクロ変数に格納するプログラムの紹介です。

以下のデータステップで、if文に記載の拡張子が.xlsxとファイル名に_Specを持つファイルの中から、最も更新日が新しいファイルの名前をマクロ変数_spec_fileに格納しています。

%let _path = hogehoge ;

filename PPASS pipe "dir /od /b &_path ";

data _null_ ;

  length _inpass $200 ;

  infile PPASS DLM='09'X DSD MISSOVER LRECL=5000 ;

  input _inpass $ ;

  if ( index(_inpass,".xlsx")>0 and index(_inpass, "_Spec")>0 ) then call symputx("_SPEC_FILE",_inpass) ;

run ;

重要なのはfilename PPASS pipe "dir &_mspec_path /b /od";の部分です。コマンドプロンプトで使用するdirコマンドをsasで使用して、その結果をinfileでデータステップに回収しています。/odで更新日時順、/bでファイル名だけ取っています。データステップに更新日時順でファイル名を持ったレコードが発生するので、一番最後を取れば更新日時が一番最後、つまり一番最新のファイルが取得できる…というわけです。便利ですね。

更新日時が一番最後のフォルダを取るときはデータステップのif文で条件を変えても行けますが、余計なファイルをはじくようにdirのオプションに/adを指定しても良いです。/adでフォルダだけ取得できるので…

これで勝手に取得できますが、念のため何をマクロ変数に入れたかは都度確認が必要です。意図通りのものと違うものがマクロ変数化されているとややこしいので…

2025年1月9日木曜日

powershellで作るlog確認ツールの話

 そろそろvbsが非推奨になるとかなんとかがで、log確認ツールをpowershellで作った。もちろんpowershellである必要は無いのだが、powershellだとwindowsで標準なので特段の準備が不要なのはとても良い(powershell5.xに限る)…7だと標準じゃないので、それ使うならpythonなり使った方が融通が利いて便利そう…

ps1ファイルの実行には癖があるが、実行用batを作るのは一つの手ではないか。ps1ファイルと同じ場所に以下の実行用batを置いておくと、batをクリックして実行することができる。ps1のファイル名は適当なので適宜変更してほしい。
set _folder=%~dp0
powershell -ExecutionPolicy RemoteSigned -File %_folder%_logCheck.ps1

実際のプログラム本体は末尾に示すとしていくつか説明を。確認したいlogファイルを収めたフォルダに、本体のps1ファイルと検索したいワードを収めた"_logChrList.txt"の二つを格納する。_logChrList.txtの中身の例は以下の画像に示す。

powershell5ではtextファイルのエンコードを自動で正しく取れないので、実行時にファイルのエンコードをs/uで入力する。これはlogファイルごとに判定しているのではなく、フォルダ内の全てのlogのエンコードを一括で指定しているので、フォルダ内に複数のエンコードが混在していると文字化けしてしまう。

実行すると同じフォルダに_LogCheckResult.txtの名前でチェック結果が格納される。フォルダ内のすべてのlogファイル内に、_logChrList.txtで指定した文字列が何件含まれているかを出力する。この際ファイル毎/文字列毎に件数を出す。上記の画像の例だとerrorの件数とwarningの件数をそれぞれ数える。面倒だったので実行結果を固定名で出しているので、同じファイル名の実行結果があると問答無用で上書きされる。

繰り返すがチェックしたいlogが格納されているフォルダに、ps1ファイルの本体と、_logChrList.txtの二つを追加して実行、実行結果が同じフォルダに_LogCheckResult.txtが出力される。この時注意としては_logChrList.txtはutf8で作成し、_LogCheckResult.txtはutf8で出力される。

以下がps1ファイルの中身。


#エンコードを入力して指定

do {

    $input = Read-Host "logのエンコード方式を選択してください ('s' で shift-jis, 'u' で utf8)"

    switch ($input) {

        's' { $encode = 'default'; break }

        'u' { $encode = 'utf8'; break }

        default { Write-Host "無効な入力です。再度入力してください。" }

    }

} while ($input -ne 's' -and $input -ne 'u')


#本体の処理

$_inpath = $PSScriptRoot ;

$_list = Get-Content -Encoding utf8 "$_inpath\_logChrList.txt"


$_resFileName = "_LogCheckResult.txt"

New-Item -ItemType file -Path $_inpath\$_resFileName -Force 


Get-ChildItem -Path $_inpath -Filter *.log -Recurse | ForEach-Object {


    # logファイルの中身を取得 

    $_content = Get-Content -Encoding $encode $_.FullName 


    # ファイル名を出力

    Add-Content -Path $_inpath\$_resFileName -Value "$($_.FullName):" 


    $count = @{}

    foreach ($_msg in $_list) {

        

        $count[$_msg] = ($_content | Select-String -Pattern $_msg).count


        #該当箇所が0件でなかったら出力

        if ($($count[$_msg]) -ne 0) {

            Add-Content -Path $_inpath\$_resFileName -Value " $_msg : $($count[$_msg])" 

        }

    }


    # ファイルの区切りを判別するために空行を挿入

    Add-Content -Path $_inpath\$_resFileName -Value " "


}


#BOMアリのutf8をbom無しに変換する powershell5は標準出力がbomアリのutf8のため変換が必要

$_outfile = -join($_inpath,"\",$_resFileName)

$_chgnobom = Get-Content $_outfile

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)

[System.IO.File]::WriteAllLines($_outfile, $_chgnobom, $Utf8NoBomEncoding)


write-host "end"

2024年12月1日日曜日

日付が欠測の日付をsas日付に変換する

 例えばjun/2023のように年月だけの日付をmmm/yyyyで表した文字値があるとして、これをsas日付に変換するにはmonyy8.formatが使えます。sas日付にさえできればjun/2023の文字を2023-06等表記を変えた文字値に変換することもできるので意外と使い道が多く助かっています。


data _null_ ;

   a = "24/jun/2023" ; b = put(input(a, date11.), yymmdd10.) ; putlog a= b= ; output ;

   a = "jun/2023"    ; b = put(input(a, monyy8.), yymmd7.)   ; putlog a= b= ; output ;

run ;

a=24/jun/2023 b=2023-06-24

a=jun/2023 b=2023-06


sas日付からyyyy-mm形式の文字値に変換する際は上記の通りyymmd.formatを使います。ややこしいのですがyymmw.formatとyymmxw.formatがそれぞれ別のものとしてあって、今回はyymmxw.formatのxの部分にdを指定してハイフン区切りの出力としています。yymms.とすると/区切りになります。

2024年11月1日金曜日

SASの勉強会に行ってきた話

 先日sasの棒発表会に参加した。偉大な主催者の人徳により今回も盛況に終わった。午後の間に発表を21本聞くのは本当に疲れた…

一番興味深いのはSASPACに関する発表。SASは作ったマクロなどを公開するには、ブログなりにコードを記載するくらいしかなかったのが、SASPACを使えば統一されたformatで公開できるというわけだ。あまりにも便利そう。そんな場所に公開できるほどの立派な代物をひとつも持っていないことが大きな問題か…

私も発表…はしたのだが、勉強会公式で資料が公開されているし、身バレが怖いのでここでは資料の公開はしない。身バレコワイ。今年も無事開催になり、私に発表の機会を与えてくれた運営の皆様には感謝の限り。来年のネタないんだがどうしよう…

2024年10月14日月曜日

sasユーザー会2024に参加した話

 なんだか数年ぶりにユーザー会に参加した。今年の会場も東大だったがキャンパスが違うとのこと。まあ何となく人の流れに乗っていくと無事ついたので良かった。自分の発表が一日目の午前であることに気が付いたのが当日3日前とかだったので、諸々の申請が間に合わず頑張って朝7時前の新幹線に乗って会場に突入。前泊…したかったな…。現地ではまさかトラック3がトラック2より大きい会場とは思わず、随分会場付近をトラック3の場所を求めてノベルティでもらったsasエナジードリンクを片手にウロウロとしてしまったのはご愛嬌。多分かなり怪しい人物になっていたと思う。…sasエナジードリンク!?恐ろしいノベルティだ。エナジーが尽きてもsasを書けということか(個人の見解です)

ぶっちゃけ今年はあまり発表するつもりはなかったが、初参加の後輩が発表すると言っているのに見捨てるわけにはいかないと思って急遽発表資料をこしらえた。かつて私が初めて発表する際には偉い人が二人も登壇していたことに随分助けられたので、今度は自分の番がきたというわけだ。自己満の領域だが私には発表登録する十分な理由だった。急遽決めたのであらゆる申請がぎりぎりだったがよく間に合った。多大なご迷惑をおかけしたことでしょう…ありがとうございました…

今年の発表も面白そうなのが多かった。文字コード、dataset-json、グラフ軸目盛の自動調整、SASでゲーム…sasでゲームの発表はぜひ聞きたかったが2日目は諸般の事情により午前で引き上げざるを得なかった。後日発表資料を読むもまあ内容にピンと来ない。ある程度powershellは触ったことがあるので何となくわかるかなーと思いきや全然である。まだまだ自分のpowershell力が足りないな…これでは立派なpowershellおじさんを名乗れないではないか。名乗る必要があるのか?pythonでも書いてろ。

なんにせよ今年のユーザー会も無事終わって何より。終わってからしばらくは咳が止まらずとんでもない体調不良に見舞われたがそれも無事収まってよかった。息か咳かどっちしてるのかわからん位の状態になるのは本当に大変だった。久しぶりの遠出に肉体が付いていかなかったのだろう。あまりにも貧弱な体には困ったものだ。毎年恒例だが来年の発表のめどが何もついていないのでこちらもどうしたものやら。結局発表するにしても締め切りぎりぎりに登録することになるのだろう…