楽天RSS+LibreOffice

メモ

現在(2021/8/1)MarketSpeed1に付属のRSSのみ対応している

準備

  • MarketSpeed(Ⅱでないほう)をインストールする。
  • 動作確認したら念のため1回再起動する
  • MarketSpeed(青いアイコン)を起動、ログインする(右上のログインボタンを押し、ユーザIDとパスワードを入力する)。
  • デスクトップかスタートメニューに「RealtimeSpreadSheet」という赤いアイコンがあるので起動*1。タスクバーに収納されたアイコンにカーソルを合わせて「RSS起動中」というツールチップが表示されればOK。(ログイン前は「RSS接続中」など別のメッセージになる)

LibreOffice動作確認

  • サンプルワークシートをダウンロードする
  • 外部リンク更新を要求されたら「Enable Update」を押す
  • セルが空白で何も表示されない場合は再起動、ファイアウォールで通信止まってないか確認、などする
    • 自分は再起動で解決した。

編集・改造

  • 編集は公式のRSS関数一覧を見ながら行う。
  • 表示更新されないときはF9(表の再計算)で更新されることがある。

*1:フォルダにRSS.exeという実行ファイルが存在するが、ショートカットは「"C:\Program Files (x86)\MarketSpeed\MLauncher\MLauncher.exe" RSS」になっている。違いは不明。

外付けテンキーのキーコード調べ(主にAutoHotKey向け)

概要

自分用便利キーを作りたく、テンキーを買った。

単純に「キーボードの左側を取り外したもの」として使おうと思っていたが、いろいろ単純にいかなかったのでちょっとメモしておく。

NumLock非同期ができない問題

Amazonレビューにもあるように、初期でNumLock非同期の挙動が発生しないことがある。実際、最初の1日はこの挙動だった。テンキー側のNumLock操作だけでは入力が変化しなかった。KeyMillで見てみると、本来「NumLock→数字キー→NumLock」となるべき時に、NumLockが送信されていない。何がおかしいのかわからず初日は終わった。

しかし、2日目いじっていると、途中で直っていた。以降全く初日の動作は再現しなかった。

原因はよくわからない。「使っているうちに安定した」としか言えない。

言いたいのは「返品する前に丸1日あれこれ打ったら直るかもよ?」という事です。

外付けじゃないテンキーとの違い

以降はちゃんと製品説明通りにNumLock非同期が働くテンキーの説明をする。

キーボードのNumLockオフ時

結論:NumLockオフ状態にホットキーを割り当てようとすると、106キーボード側の個別EndやHomeキーを巻き込むことになる。

テンキー1(NumPad1/NumpadEnd)を例にとる。

キーボード テンキー
テンキーNumLockオフ NumpadEnd End
テンキーNumLockオン NumpadEnd NumPad1(前後NumLock挿入)

おわかりいただけただろうか。

キーボード側のNumLockはオフのままのため、出力はNumpadEndで変化しない。これはいつも通り。

外付けテンキーはNumLockオン時はテンキー1(実際はNumLock→Numpad1→NumLock)になる。これも、キーボードのNumLockオン状態と同じ。

一方、NumLockオフ時、テンキーはNumpadEndにならない。テンキーの左側にある、単独のEndキーと同じキーコードを出す。

試しにAHKで、

End::
    msgbox "test"
Return

というのを書いてテンキーを押すと、ちゃんとダイアログが出る。

ということで、NumLockオフ状態のテンキーは、キーボードのNumLockオフテンキーとはキーコードが異なる*1

(これで1日嵌まった)

強制NumLock無効化

結論:外付けテンキーのNumpadEndなどを出力させるには、力技が必要

外付けテンキーのNumLockオン時は「NumLock→数字→NumLock」となる。

これを無効化しようとして

NumLock::
Return

というスクリプトを書いた*2。キーを押して数字が出ないことを確認*3。この状態で確認したキーコードを表に追加すると以下のようになる。

キーボード テンキー テンキー(NumLock無効化)
NumLockオフ NumpadEnd End End
NumLockオン NumpadEnd NumPad1(前後NumLock挿入) NumpadEnd

NumLockをオフにした状態と同じ、ではなく、NumpadEndを出力する。

これはこれで使いようもあるが、AHKの仕様上、たまにNumLockを無効化しきれず、数字キーに切り替わってしまうことがある。手元では「本当にたまに」しか起きないが、アプリケーションより下層レイヤの現象なので、場合によっては頻繁に起きて、使い物にならないかもしれない。

結論

  • キーボードのテンキーと外付けテンキーはイコールではない
  • AHK割付を考えてる場合にはいろいろ工夫が必要

*1:推測になるが、ノートPCのFn同時押しのEndがNumpadEndでないEndなのと関係ある実装なのかもしれない。

*2:全く使えないのは困るのでPauseなどにNumLockを割り当てておく

*3:たまにすり抜ける(AHKの仕様)

コマンドプロンプト バッチファイルの色々

よく使うものを。

バッチファイルのある場所へカレントフォルダへ移動する。

ショートカットからの起動で作業フォルダが変化している時など、これを先頭に入れておくと楽。

%~d0
cd %~dp0

%0が実行中のバッチファイル名、%~d0がバッチファイルのドライブ*1と「:」、%~p0がパス名(\以降。pathのp)に展開される。

詳しく知りたいときはhelp for内に一覧があります。

別記事:任意のフォルダでコマンドプロンプトを起動する方法 - 永遠に未実装

日付や時間表示

ストップウォッチやログ記録に。

>echo %DATE% %TIME%
2021/05/03  12:46:50.75

文字列操作(おすすめしない)

%変数名:置換前文字列=置換後文字列%で可能。

可読性が落ちる=自分の首を絞めることになるので非推奨。普通にプログラムを書いたほうが楽できる。機能では正規表現以下。

ログファイルを日単位で名前変更したいとき、くらいしか実用的な使い道は無い。

>set temp=aaa
>echo %temp:a=b%
bbb

>echo %TIME::=-%
12-46-50.75

>echo filename_%DATE:/=%.txt
filename_20210503.txt

一時的にPATHを変更してプロンプトを開く

環境変数を追加するのが不安な人に。

PATHの変更はこのウィンドウ内だけで有効。 バッチファイルの場合には最後にcmdを書いてウィンドウを開いたままにする。exitやウィンドウを閉じれば終了。

> set PATH=%PATH%;C:\Program Files\AdoptOpenJDK\jdk-13.0.1.9-hotspot\bin;
@rem バッチファイルの場合
set PATH=%PATH%;C:\Program Files\AdoptOpenJDK\jdk-13.0.1.9-hotspot\bin;
cmd

標準エラー出力のリダイレクト

1が標準出力で、2標準エラー出力

標準エラー出力を、標準出力へリダイレクトしたいときは、&をつけて2>>&1とする。

どうしてこういう仕様なのかはよくわからない。

> someapp.exe >>log.txt 2>>error.txt
> someapp.exe >>log.txt 2>>&1

最後に

上記は記号や数字を使った記述が多く、自然と難読化します。一方で使用頻度の観点からすると忘れやすく、労力かけて暗記するメリットも少ないです(仕事で毎日使うような場合を除く)。すでに書けるプログラミング言語があるなら、バッチファイルの編集は避け、使える言語で処理を書いたほうがこの先有利になるかもしれません。機能追加の面でも新しい言語のほうが有利なのと、2種類を使い分けるより、得意な1種類の言語に集中したほうが、勉強の効率が良いと考えているからです。

個人的意見ですが、ご参考にお願いします。

*1:driveのd

outlookの「予定表の追加」で登録した予定表たちを(無理矢理)移植する

概要

  1. outlook予定表の設定を既定の.pstファイルに保存していたが、別ファイル(.ost)へ変更することになった。使っていた.pstファイルには、共有のアドレス帳から追加した他人の予定表が50件近く入っていた。
  2. インポートメニューからは色々やっても引き継げなかった。
  3. 正攻法が見つからなかったので、後述の様に(かなり無理矢理)アドレスリストを作って、一括登録した。
  4. 予定表グループや並び順は復元できなかったので、手動編集した。

詳細

まず、 C:\Users\<ユーザー名>\AppData\Local\Microsoft\Outlook\16 を開いて確認する。隠しフォルダなので、見つからなかったらエクスプローラの設定を確認する。「outlook\16」部分はOffice 2019固有だと思うので、別のバージョンでは違うかもしれない。

このフォルダの中に「AutoD.<アカウント名>.xml」というファイルがある*1。不要なファイルもあるが、多くのファイル名が「予定表」に登録しているアカウント名と一致している。

このファイル名からをテキストにして使ってしまえばいい、という話。

手順

  1. 適当なフォルダでコマンドプロンプトを開いて以下を実行する。「<ユーザー名>」部分は各PCのユーザ名が入る*2
> dir /A H /b C:\Users\<ユーザー名>\AppData\Local\Microsoft\Outlook\16 > namelist.txt
  1. 出力した namelist.txtには、ファイル名の一覧が入っている。
  2. テキストエディタで「AutoD.」と「.xml」を一括置換して、アカウント名部分だけ残す。
  3. 不要なアカウント名の行は手作業で消す(これは予定表の追加後ででもよい。)。
  4. 予定表「予定表の追加」→「アドレス帳から」で、編集したテキストファイルを貼り付ける。

この方法だと予定表グループや並び順はぐちゃぐちゃになるので、グループや整列は自力で行う。

時間が無かったので、マクロやプログラムを使う方法は避けた*3VBAならグループ設定なども抽出できるのかもしれない。

*1:よくわかっていない。なんかのキャッシュらしい

*2:簡単に言うと、隠しファイル含め、指定フォルダのファイル名だけ表示しろ、というコマンド。

*3:検索したけど上手く見つけられなかった

コマンドプロンプト+WSHの簡易タイマー

PowerShellやVBSならダイアログボックス上でカウントダウンできると思うけれど、間に合わせで思いついたままに書いてみた。

DOS窓で分数を指定し、指定時間たったらポップアップを表示するだけ。カウントダウン中にcolorで色を変更するのは他のウィンドウと区別するため*1だけれど、好みの問題。

ショートカットをデスクトップに置いて使うことを想定しています。ショートカットのプロパティでウィンドウの座標やサイズ、文字サイズを設定することができるので、画面隅に小さく表示して使うこともできます(最前面表示などはおそらくできません)。

timer.bat

@echo off
set /p TIMER_MINUTE=時間(分)を入力: 

rem timeoutのために分を秒に変換する
set /A TIMER_SECOND=TIMER_MINUTE*60

title タイマー %TIMER_MINUTE%color f0

timeout /T %TIMER_SECOND% /NOBREAK

rem ポップアップ表示
wscript timer.vbs %TIMER_MINUTE%

timer.vbs

Wscript.echo ("" & Wscript.Arguments(0) & " 分経ちました!")

*1:自分の環境ではコマンドプロンプトのウィンドウを複数開いていることが多い

Excel VBAで正規表現オブジェクトを使ってみる(VBScriptのRegExpオブジェクトを呼び出す)

お試しで書いてみたもの。計算結果のセルを目立たせるため、sum関数のあるセルの背景色を一括変更しようと作ったものです。

Excel VBA単体では正規表現が使えないため(Like演算子で代替可能なこともある*1 )、VBScirptのエンジンを呼び出して、VBRegExpオブジェクトを使用します。

  • CreateObjectを使う方法とエディタで参照設定して使う方法がありますが、今回は後者を使用しています。
    • 参照設定は実行環境(Excelやライブラリのバージョン)による互換性問題がありますが、大勢・複数のPCで使用する予定がなければあまり問題は起きない…はずです。
    • Objectオブジェクト*2を乱立するのは避けたかったため。Regexp以外のオブジェクトが増えたときに取り間違いを起こしやすい、気がします。
  • メソッドは、RegExp.testとRegExp.execute、RegExp.Replaceの3種類。
    • testは一致不一致をbooleanで返します。
    • executeを使うと結果がMatchesコレクションで返され、一致回数や後方参照など詳細解析ができます。
    • Replaceは文字列置換。

参考

Sub regexpの実験()
'RegExpオブジェクトとMatchesコレクション(Matchオブジェクト)の使い方テスト  
    
    Dim test_regex As RegExp
    Dim r As Range
    
    Set test_regex = new RegExp  
    
    'sum関数のあるセルの背景色を変える
    With test_regex
        .Pattern = "SUM\(" '正規表現のパターン。記号のエスケープ注意(特に2重引用符)
        .IgnoreCase = True '大文字小文字を区別しないときはTrue。デフォルトfalse。
        .Global = True     '/g の設定。デフォルトFalse
        For Each r In ActiveSheet.UsedRange
            If .test(r.Formula) Then r.Interior.ColorIndex = 3
        Next r
    End With
    Set test_regex = Nothing 'オブジェクト開放?      

End Sub

*1:ただ、Like演算子正規表現では細かいところで違い、両方使うと混乱する

*2:日本語として微妙

Perlの多次元配列の初期化を1行で書いてみたけど、やめたほうがいい

いきなり結論

3次元配列を0初期化する場合。

@multi_array=map{[map{[map{0}(0..2)]}(0..4)]}(0..7); #multi_array[8][5][3]

でも、普通にこっちのほうがいいよ

my @array;
for my $i(0..7){
    for my $j(0..4){
        for my $k(0..2){
            $array[$i][$j][$k]=0;
        }
    }
}

やめたほうがいい理由

読みにくい、書きにくい

1行にmapが3回も出てきます。中括弧と角かっこのネストも多く、間違いやすいです。

素数がわかりにくい

作りたい配列の要素数は[8][5][3]ですが、コードは添え字の数字が逆の順に出てきます。コメントなど、何らかの追加情報がないと誤解を招きます。

これを書いた本人も、末尾コメントがなければ理解できる自信がないです。

ゼロ初期化以外が書きにくい(拡張性がない)

中に複雑な初期値を書くことができません、少なくともif文を追加するのは向きません。 一から書いた、初版のプログラムでは、全ての要素は初期値ゼロでいいかもしれません。しかし、プログラムに機能を追加・拡張していくと、「偶数行だけ別の値にしたい」「規則的な値を入れたい」となることは時々あります。この初期化の後にfor文で追加の初期化を書けばよいかもしれませんが、(結果論では)最初からfor文で書いておいたほうがシンプルです。

よく考えると利用機会が限られる

3次元配列って必要でしょうか。多数のデータ、複雑な構造を持つデータなら、オブジェクトの配列や、あるいはデータベースで表したほうが有利なことはないか、考える余地はあります。これはプログラムの文法というより、構成や設計寄りの検討になります。

数学の3次元行列そのものを扱うときには必要なので、要は適材適所、です。

最後に

短く書くことはプログラマの美徳なこともありますが「短く『簡潔』」であることも重要だと思います。また、あまり省略しすぎると追記(拡張)に耐えられないこともあります。

短くて難しい記述は長くて読みやすい記述とトレードオフとも言えるので、凝った記述に凝りすぎないようにしましょう。なにごともほどほどに。

付録:いちおう解説

普通に書いた場合(再掲)。

my @array;
for my $i(0..7){
    for my $j(0..4){
        for my $k(0..2){
            $array[$i][$j][$k]=0;
        }
    }
}

ところで、formapについて、次の2つの式は同じ結果になります。

for my $i (0..9){$array[$i]=0;}
@array=map{0](0..9); #same

それを使い、一番内側のformapにします。

for my $i(0..7){
    for my $j(0..4){
            $array[$i][$j]=map{0}(0..2); #(0,0,0)のリスト
    }
}

同じように2次元目も。2次元配列=リファレンスの配列なので、mapの結果に角括弧をつけ、配列のリファレンスとして返します。

for my $i(0..7){
    $array[$i]=map{[map{0}(0..2)]}(0..4); #[0,0,0]のリファレンス×5。
}

あと一息。

@array=map{[map{[map{0}(0..2)]}(0..4)]}(0..7);

おしまい。