Hidemaru Q and A

第I部〜秀丸エディタQ&A集
 質問番号順Q&A(マクロ編)


前へ:[HMM0001A]〜[HMM0050A]


[HMM0051A]

●version キーワードの使い道は?

Q. 秀丸マクロの新しいバージョンの機能を実装しているかどうか調べるために version キーワードを使ってみましたが、文法エラーが回避できません。

A. version キーワードを使って、あるバージョンから実装されたマクロ命令を使うかどうか振り分けることは、できそうに思えますができません。秀丸は少なくとも現在の仕様では、マクロを実行前に一旦すべて文法チェックする仕様のようなので、version を使っても、バージョン判別ルーチンが実行されること無く、文法エラーがあるというダイアログを出して止まってしまいます。
では version の使い道が無いかというとそうでもなく、あるバージョンの秀丸で当該のマクロ実行に致命的なバグがあることが既に分かっている場合に、そのバージョンの秀丸での実行を禁止させるために使うことができます。

[HMM0052A]

●秀丸95のレジストリ操作と16bit版秀丸の共通化

Q. 16bit版秀丸ではhidemaru.iniに設定が保存されていましたが、秀丸95ではレジストリに保存されるようになりました。どちらの秀丸でも動作できる方法はありますか?

A. getinistr/getininum 等で、ファイル名を "hidemaru.ini" にすると、秀丸95ではレジストリに対して読み書きをします。秀丸95と16bit版秀丸両用のマクロを作る場合や、レジストリについてよく分からない人(^^;)は、これらのマクロ命令を使うようにします。秀丸マクロヘルプの getinistr/getininum のところに記述があります。

[HMM0053A]

●ワードラップと折り返し

Q. 秀丸によって折り返し文字数のところで折り返された行頭のところで空白を挿入しようとしても、挿入されないことがあるようなのですが……。

A. ワードラップ機能によって折り返されている場合は、挿入した空白が前行の行末に付きますので、それが正常な動作です。ワードラップの設定がされているかどうかはキーワードでは分からないので、以下のように設定ファイルから参照します。
//(例)
if (getininum("hidemaru.ini","Env","Wordwrap")==1){
// ワードラップ時の処理
}

[HMM0054A]

●16bit版秀丸のmovetolinenoのバグ

Q. 16bit版秀丸で、movetolineno 文でテキストの最終行に飛ばすように指定しても、その1つ前の行に飛んでしまいます。

A. これは16bit版秀丸の一部のバージョンにあったバグです。秀丸95では起きないのですが、秀丸95でも16bit版秀丸でも動作する汎用のマクロを作ろうとすると避けて通れません。(^^;)
 このバグの回避方法の例を以下に示します。
  1. 次行行頭への移動(例:movetolineno 0, lineno + 1;)の場合
    以下の3行を組み合わせて代用できます。
    golineend2;
    down;
    golinetop2;
    前行行頭への移動等も同様にできます。
  2. 最終行にだけ飛べないんですから、いっそのこと最終行に改行を1つ挿入してマクロの最後で削除する、という手があります。
  3. 「絶対に最終行には飛ばさない」という自信がある場合はそのまま使えます(^^;)

[HMM0055A]

●文章作成日時を挿入するには?

Q. 編集中のファイルに現在の日時を挿入したいのですが、何か簡単な方法はないでしょうか?(手で書くのでは不便です)

A. 以下のようなマクロを使えば簡単に実現できます。
//------- サンプルマクロ -------//
insert date + " " + time + "\n";
endmacro;
// ---------------------------- //

[HMM0056A]

●複数のウィンドウ間を移動したい

Q. openfile 文でファイルを開くと、その後の処理は今開いたファイルに対して行われますが、元のファイルに戻るにはどうしたらよいのでしょうか?

A. 既に開かれている秀丸のウィンドウをアクティブにする(画面の一番手前に持ってくる)には、setactivehidemaru 文を使います。
//------- サンプルマクロ -------//
// 元のファイルに戻る
#hwnd = hidemaruhandle( 0 ); //元ウィンドウのハンドルを取得する
openfile "c:\\hidemaru\\install.txt"; //別ファイルを開く
//ここに c:\hidemaru\install.txt 上での処理が入る。
setactivehidemaru #hwnd; //元のウィンドウに戻る
endmacro;
// ---------------------------- //

※ hidemaruhandle() 関数についてはマクロヘルプの「秀丸管理」の説明と「●setactivehidemaru 文の引数」を参照して下さい。


[HMM0057A]

●秀丸ウィンドウを閉じたい

Q. マクロから開いたウィンドウを閉じて元のウィンドウに戻りたいのですが。

A. 手順としては、元のウィンドウに戻ってからウィンドウを閉じる、となります。下記のサンプルを参考にして下さい。
//------- サンプルマクロ -------//
#hwnd = hidemaruhandle( 0 ); //元ウィンドウのハンドルを取得する
openfile "c:\\hidemaru\\install.txt"; //別ファイルを開く
#hwnd_new = hidemaruhandle( 0 ); //ウィンドウハンドルの取得
//ここに c:\hidemaru\install.txt 上での処理が入る。
setactivehidemaru #hwnd; //元ウィンドウに戻る
closehidemaru #hwnd_new; //別ウィンドウを閉じる
endmacro;
// ---------------------------- //
※ closehidemaru 文の代わりに closehidemaruforced 文を使えば、編集中のウィンドウも(編集内容を破棄して)強制的に閉じる事ができます。

[HMM0058A]

●setactivehidemaru 文の引数

Q. setactivehidemaru 文を使って編集ウィンドウを切り替えたいのですが、使い方がよく分かりません。

A. setactivehidemaru 文には秀丸ウィンドウの「番号」か「ウィンドウハンドル」を指定します。

[解説]

  1. ウィンドウ番号
    秀丸ウィンドウの「番号」とは、秀丸のウィンドウを画面手前から順に数えた番号になっています(一番手前が 0 です)。ファイル名からウィンドウ番号を取得するには findhidemaru() 関数を使います。
    //------- サンプルマクロ1 -------//
    // "c:\\hidemaru\\install.txt" のウィンドウ番号を取得する
    $file = "c:\\hidemaru\\install.txt";
    #h_order = findhidemaru($file);
    message $file + " のウィンドウ番号は " +
    str(#h_order) + " です。";
    if( #h_order != -1 ) setactivehidemaru #h_order; //切り替え
    endmacro;
    // ---------------------------- //
    ※ ファイルが開かれていない場合は、ウィンドウ番号は -1 になります。

  2. ウィンドウハンドル
    1. で説明したウィンドウ番号は、setactivehidemaru を繰り返し使用してウィンドウの切り替えを行うと変化してしまいます。いちいち findhidemaru() 関数を使ってウィンドウ番号を取得してもいいのですが、「ウィンドウハンドル」を取得しておけば(ウィンドウを閉じない限り)そのウィンドウを一発で指定できます。
    //------- サンプルマクロ2 -------//
    // "c:\\hidemaru\\install.txt" のウィンドウハンドルを取得する
    $file = "c:\\hidemaru\\install.txt";
    #h_wnd = hidemaruhandle(findhidemaru($file));
    message $file + " のウィンドウハンドルは " +
    str(#h_wnd) + " です。";
    if( #h_wnd != 0 ) setactivehidemaru #h_wnd; //切り替え
    endmacro;
    // ---------------------------- //
    ※ hidemaruhandle() 関数の引数にはハンドルを取得したいウィンドウのウィンドウ番号を指定します。ウィンドウが存在しない場合(ウィンドウ番号が -1 の場合)、hidemaruhandle() 関数は 0 を返します。

  3. findhidemaru() 関数を使う場合の注意点
    findhidemaru() 関数の引数にアクティブウィンドウ(ウィンドウ番号 0)のファイル名を指定した場合も(ウィンドウが存在しない時と同様に) -1 を返すため、上記のサンプルマクロを c:\hidemaru\install.txt 上で実行すると「c:\hidemaru\install.txt のウィンドウ番号は -1 (ウィンドウハンドルは 0)です。」と嘘(^^;を言われてしまいます。
    例えばアクティブウィンドウのウィンドウハンドルを取得したい場合は、
    #hwnd_act = hidemaruhandle(findhidemaru(filename));
    ※ filename には現在のウィンドウのファイル名が入る
    (「●「キーワード」とは?」を参照して下さい)。
    ではなく
    #hwnd_act = hidemaruhandle( 0 );
    と指定しなければ正しく動作しません。

[HMM0059A]

●ウィンドウを見えなくしたい

Q. マクロから別のウィンドウを開いているのですが、そのウィンドウを見えなくする事は可能でしょうか?

A. 起動オプションの「ステルス起動(/h)」を使えばできます。
//------- サンプルマクロ -------//
// "c:\\temp\\00work00.$$$" をステルスモードで起動する
#hwnd = hidemaruhandle( 0 ); //元ウィンドウのハンドルを取得
$temp_file = "c:\\temp\\00work00.$$$";

openfile "/h " + $temp_file; //ステルスモードで開く
#hwnd_stealth = hidemaruhandle( 0 ); //ステルスウィンドウのハンドル

//ここに c:\temp\00work00.$$$ 上での処理が入る。
// (ここで実行される処理は画面では見えない)
setactivehidemaru #hwnd; //元ウィンドウへ移動
closehidemaruforced #hwnd_stealth; //ステルスウィンドウを閉じる
endmacro;
// ---------------------------- //
※ ステルスモードで開いたウィンドウは「必ず」マクロの中で終了させて下さい!!

なお、ステルスウィンドウに対する findwindow() 関数は失敗する場合が多いので、なるべく開いた「直後」に hidemaruhandle( 0 ) でウィンドウハンドルを取得しておきましょう。


[HMM0060A]

●「キーワード」とは?

Q. 現在マクロを実行しているウィンドウに関する情報を取得したいのですが。

A. 秀丸マクロにはそのような情報を格納している「キーワード」と呼ばれる特殊な変数が用意されています。マクロヘルプの「式について」→「内部的な値を表現するキーワード」を参照して下さい。

※ なお、キーワードの値は「ウィンドウ」毎に定義されています。
(例: filename というキーワードには、そのウィンドウで開かれているファイルのファイル名が入っている。)


[HMM0061A]

●「キーワード」の使い方

Q. 「キーワード」の使い方がよくわかりません。

A. 「キーワード」の使い方は普通の変数("$"または"$$"で始まる文字列変数、"#"または"##"で始まる整数型変数)の使い方と同じです。つまり、文字列操作関数の引数に使用したり、算術式の中に入れたり、別の変数への代入等ができます。但し「キーワードへの代入」はできません(以下の例を参照して下さい)。

(例)ファイル名を変えるのに filename というキーワードの値を変えようとした。
filename = "c:\\temp\\test.txt"; //(エラー!!)
※ この場合は changename 文を使用して下さい。


[HMM0062A]

●フォルダの存在を確認したい

Q. existfile() 関数を使えばファイルの存在を確認できるようですが、フォルダの存在を確認する事はできないですか?

A. existfile() 関数の引数にフォルダ名+"nul"を指定すればよいです。
if( existfile("c:\\temp\\nul") )
message "c:\\temp フォルダは存在します。";
また、ちょっと面倒ですが「秀まるおのマクロサーバ」を使ってもできます(秀丸エディタの作者サイドからはこちらが推奨されています)。
以下はそのサンプルです。
//------- サンプルマクロ -------//
// c:\temp というフォルダがあるかどうかを調べる
run hidemarudir + "\\macserv.exe";
ddeinitiate "HideMacroServer", "FileService";
ddeexecute "enumdir c:\\*.*";
##found = 0;
##i = 0;
while( 1 ){
$$folder[##i] = dderequest("findnext");
if( $$folder[##i] == "" ) break;
else if( $$folder[##i] == "temp" ){
##found = 1;
break;
}
##i = ##i + 1;
}
ddeexecute "exit";
if( ##found ) message "c:\\temp フォルダは存在します。";
else message "c:\\temp フォルダは存在しません。";
endmacro;
// ---------------------------- //
※このサンプルでは「秀まるおのマクロサーバ(macserv.exe)」が秀丸エディタのフォルダにインストールされている事を仮定しています。

[HMM0063A]

●メニュー項目を揃えたい

Q. menu 文等で各項目をきちんと揃えて表示したいのですが?

A. ワープロソフトでやるような自由な「タブ指定」はできませんが、以下の様なやり方で何とか(^^;揃える事はできます。
//------- サンプルマクロ -------//
menu "1.   Test 1",
     "10.  Test 2",
     "100. Test 3";
menu "1.\tTest 1",
     "10.\tTest 2",
     "100.\tTest 3"; //タブ(\t)は一つだけ使用可
endmacro;
// ---------------------------- //
※ 上記の2つの表示の違いを比べてみて下さい。

[HMM0064A]

●メニューに色を付けたい

Q. menu 文等で、項目の文字列の色を変える事はできますか?

A. できません(裏ワザを知ってる方はご一報下さい(^^;)。

[HMM0065A]

●menuarray 文の引数を自由に設定したい

Q. menuarray 文等で、第1引数の配列の指定を途中(ex. $a[2])からしたり、途中で止めたりする事はできませんか?

A. まず、
menuarray $a[2], 2;
の様に配列の途中から指定する事はできません。 途中で止めるには、第2引数の配列の数を調整すればできます。
//------- サンプルマクロ -------//
$a[0] = "1.\tTest 1";
$a[1] = "2.\tTest 2";
$a[2] = "3.\tTest 3";
menuarray $a, 2; //「2. Test 2」までしか表示されない
endmacro;
// ---------------------------- //

[参考]
あまり使う事はないでしょうが(^^;、2次元配列を使えば以下の様な事もできます。
//------- サンプルマクロ -------//
$a[0][0] = "メニュー1の項目1";
$a[0][1] = "メニュー1の項目2";
$a[1][0] = "メニュー2の項目1";
$a[1][1] = "メニュー2の項目2";
menuarray $a[0], 2; //「メニュー1」の表示
menuarray $a[1], 2; //「メニュー2」の表示
endmacro;
// ---------------------------- //


[HMM0066A]

●Windows3.1で動いたマクロがWindows95で動かない?

Q. Windows3.1では正しく動いていたマクロを秀丸95で実行したら「バッファが溢れた」と言われ、動かすことが出来ません。秀丸マクロは上位互換のはずですが…。

A. 秀丸95のごく初期のバージョンでは、マクロ言語の内部処理が32bit化されたのにバッファ量がそのままだったので、実質的にバッファが狭くなっていたようです。Ver.2.13 以降ではバッファのサイズが倍増されおり、まったく問題はありません。

[HMM0067A]

●マクロで引用符を取得するには

Q. 秀丸マクロの中で、秀丸で設定されている引用符を文字列として取得したいのですが、どうすればいいですか?

A. 以下のマクロ例を参考にしてください。

// (例) 引用符を取得するマクロサンプル ---------------------

$inyoufuini = getinistr("HIDEMARU.INI", "Env", "RefMark");

#inyoufuiniLen = strlen($inyoufuini);
if (#inyoufuiniLen <= 2) {

$inyoufu = "";
} else {
$inyoufu = midstr($inyoufuini, 1, #inyoufuiniLen - 2);
}

message $inyoufu;

// (ここまで)-----------------------------------------------

[解説]
引用符の文字列は、16bit版秀丸では、HIDEMARU.INIの[Env]セクションの RefMark= に、@ @ でくくられて格納されていますので、不要な @ @ を後で削除します。
秀丸95でも互換性が保たれていますので、このままで動作します。
ただし、秀丸インストール直後には RefMark= キー自体が存在していないので、処理内容によっては注意が必要な場合があります。


[HMM0068A]

●マクロ中の演算子の意味は?

Q. 秀丸マクロに使える演算子がヘルプに書いてありますが、私はC言語を知らないので、演算子の意味がわかりません。(^^;)

A. 以下の表とマクロ例を参考にしてみてください。


算術演算子
+加算
-減算
*乗算
/除算(商)
%剰余(MOD)
論理演算子
<=(右辺)は(左辺)以上
>=(右辺)は(左辺)以下
<(右辺)は(左辺)より大きい
>(右辺)は(左辺)より小さい
!=(右辺)は(左辺)と違う
==(右辺)は(左辺)と同じ
&&AND:(左辺)かつ(右辺)
||OR:(左辺)または(右辺)
!NOT:(右辺)ではない
ビット演算子
|OR
&AND
^XOR


[HMM0069A]

●マクロ処理中にダイアログボックスを出す方法

Q. マクロ処理中にダイアログボックスを出して、「処理中です」と表示させたいのですが?。

A. 全ての場合についてできるわけではないですが、while ループかなんかで処理をするような場合については「秀まるおのマクロサーバ」を使って以下の様な感じで何とかなるんじゃないでしょうか?

以下の例では、"0"〜"9"の文字を繰り返し1000個まで表示させます。「中止」ボタンをクリックすると処理を中断します。

// マクロサーバで常にダイアログを表示させるサンプル

run "macserv.exe";
ddeinitiate "HideMacroServer", "AllService";
ddepoke "newdialog", "20,秀丸マクロ";
ddepoke "newcontrol", "text,,処理中です";
ddepoke "newcontrol", "defbutton,,中止";
ddepoke "notify", "10";
$item = "";
ddestartadvice "dlgresult", $item;
ddeexecute "dialog lastactiveparent";

while( 1 ){

ddewaitadvice $item, 10;

// 「中止」ボタンが押されたら終了する
if( $item != "" ) break;

// 元々のコード例:ここから
// 終わったら break でループを抜ける
#n = #n + 1;
#m = #m + 1;
if (#n > 9) #n = 0;
insert str(#n);
if (#m > 1000) break;
// 元々のコード例:ここまで

}
ddeexecute "enddialog";
ddestopadvice "dlgresult";
ddeexecute "exit";
endmacro;

// (ここまで)-----------------------------------------------


[HMM0070A]

●入力チェック、変数チェックを簡単に行う方法

Q. 入力チェック、変数のチェックを行うとき if の文が複雑になります。それをできるマクロの関数はありますか ?

A. チェック専用の関数はありませんが、入力チェックをするときに、色々な値がある場合には、if で strstr 関数を使用すると文が簡単になります。

// a1.mac ---------------------

$wk1 = input("血液型を入力してください!","");
if( $wk1 == "O" || $wk1 == "A" || $wk1 == "B" || $wk1 == "AB" ){

message "血液型 : " + $wk1;
} else {
message "間違った血液型です !";
}

endmacro;

// (ここまで)-----------------------------------------------

// a2.mac ---------------------

$wk1 = input("血液型を入力してください!","");
if( strstr("|O|A|B|AB|","|"+$wk1+"|") != -1 ){

message "血液型 : " + $wk1;
} else {
message "間違った血液型です !";
}

endmacro;

// (ここまで)-----------------------------------------------

この a1.mac と a2.mac は同じ結果となります。"|" は、一般的には区切文字 (区切記号) と呼ばれ、入力文字としてありえない文字を使用すると文が見やすくなります。全角文字 (Shift-JIS の場合) を処理するときには、! - / などの 0x40 (16 進数) より小さな文字を区切文字にします。

全角半角の文字が混在するときは完璧なチェック方法にはなりませんが、実用レベルには耐えるでしょう。


[HMM0071A]

●入力が数値、整数であるかのチェック方法

Q. 簡単なニューメリックチェック法(入力が数値、整数であるかのチェック)はありませんか ?

A. 入力がニューメリック(数値、整数)であるかのチェックは厳密に行うと複雑なロジックになりがちです。ここでは簡単なチェック方法を示します。

// (例) ---------------------

$wk1 = input("数値を入力してください!","");
if( $wk1 == str(val($wk1)) ){

message "数値 : " + $wk1;
} else {
message "数値ですか ! \n" + $wk1;
}

endmacro;

// (ここまで)-----------------------------------------------

入力文字列を、val 関数で数値にして、次に str 関数で文字列にして、最初の入力文字列と比較しています。完璧なチェック方法ではありませんが、実用レベルには耐えるでしょう。この例では、+ 符号、全角文字 (数字) の考慮はありません。


[HMM0072A]

●2バイト文字の判断方法

Q. カーソル位置にある文字が、1バイト文字か2バイト文字かを判断するにはどうしたらいいでしょうか?

A. 秀丸の内部キーワード「code」を使い、ビット演算を使って2バイト文字かどうかを判断することで、可能です。

// サンプルマクロ(ここから)
#Code = code;
if( #Code == 0 )
{ // フリーカーソルで改行以降
message "改行以降";
}
else if( #Code == 0x09 )
{ // タブ
message "タブ";
}
else if( #Code == 0x0d )
{ // 改行
message "改行";
}
else if( #Code == eof )
{ // EOF
message "EOF";
}
else if( ( code & 0xff00 ) != 0 )
{ // 2バイト文字
message "2バイト文字";
}
else
{
message "1バイト文字";
}
endmacro;
// サンプルマクロ(ここまで)

文字列変数の中の文字列をバイト単位ではなく文字単位で扱いたい場合は、[HMM0073A] ●文字列をバイト単位ではなく文字単位で扱う を参照して下さい。


[HMM0073A]

●文字列をバイト単位ではなく文字単位で扱う

Q. 「strlen」等の文字列操作関数はバイト単位となっていますが、文字単位で扱うことはできないでしょうか?1バイト文字と2バイト文字が混在している時に、とても困ります。

A. 秀丸の関数「ascii」は先頭文字が2バイト文字の場合に値を2バイトで返すので、ビット演算を使って2バイト文字かどうかを判断することで、可能です。
なお、秀丸マクロでは文字コードをSHIFT-JISで扱っているため、文字列中の任意の場所の文字コードを判別するには、文字列の先頭から順番に検索する必要があります。

// サンプルマクロ(ここから)
$Str = "AABBCC";

call leftstr2 $Str, 2;
message "左2文字=[" + $$return + "]";

call rightstr2 $Str, 2;
message "右2文字=[" + $$return + "]";

call midstr2 $Str, 2, 2;
message "中2文字=[" + $$return + "]";

endmacro;

//----------------------------------
// 文字列の左側部分
//
// (引数) $$1: 文字列、##2: 文字数
// (返り値) $$return: 文字列
//----------------------------------
leftstr2:

call midstr2 $$1, 0, ##2;
return $$return;
//----------------------------------
// 文字列の右側部分
//
// (引数) $$1: 文字列、##2: 文字数
// (返り値) $$return: 文字列
//----------------------------------//
rightstr2:
call strlen2 $$1;
##Pos = ##return - ##2;
if( ##Pos < 0 )
{
##Pos = 0;
}
call midstr2 $$1, ##Pos, ##2;
return $$return;
//--------------------------------------
// 文字列の中央部分
// (引数) $$1: 文字列、##2: 取得位置、##3: 文字数
// (返り値) $$return: 文字列
//--------------------------------------
midstr2:
$$Str = "";
##StrLen = strlen( $$1 );
##I = 0;
##J = 0;
while( ##I < ##StrLen )
{
if( ##J >= ##2 )
{
break;
}
if( ( ascii( midstr( $$1, ##I, 2 ) ) & 0xff00 ) != 0 )
{ // 2バイト文字
##I = ##I + 2;
}
else
{
##I = ##I + 1;
}
##J = ##J + 1;
}
##J = 0;
while( ##I < ##StrLen )
{
if( ##J >= ##3 )
{
break;
}
$$Wk = midstr( $$1, ##I, 2 );
if( ( ascii( $$Wk ) & 0xff00 ) != 0 )
{ // 2バイト文字
##I = ##I + 2;
}
else
{
$$Wk = midstr( $$1, ##I, 1 );
##I = ##I + 1;
}
$$Str = $$Str + $$Wk;
##J = ##J + 1;
}
return $$Str;
//------------------------------------------
// 文字列の長さ
// (引数) $$1: 文字列
// (返り値) ##return: 文字列の長さ
//------------------------------------------
strlen2:
##StrLen = strlen( $$1 );
##I = 0;
##StrLen2 = 0;
while( ##I < ##StrLen )
{
if( ( ascii( midstr( $$1, ##I, 2 ) ) & 0xff00 ) != 0 )
{ // 2バイト文字
##I = ##I + 2;
}
else
{
##I = ##I + 1;
}
##StrLen2 = ##StrLen2 + 1;
}
return ##StrLen2;
// サンプルマクロ(ここまで)


[HMM0074A]

●文字列の後方から文字列を検索

Q. 文字列の後方から文字列を検索する方法はありますか?ロングファイル名での拡張子取得で、「.」を後方から検索したいのですが。

A. 文字列の先頭から文字列が見つからなくなるまで複数回検索することで可能です。

// サンプルマクロ(ここから)
$FNm = basename2;
call strstr2 $FNm, ".";
#Pos = ##return;
if( #Pos == -1 )
{ // 拡張子なし
$Exp = "";
}
else
{
$Exp = rightstr( $FNm, strlen( $FNm ) - #Pos - 1 );
}
message "拡張子は[" + $Exp + "]です。";
endmacro;
//----------------------------------------------------------
// 文字列の後方から文字列を検索
//
// (引数) $$1: 文字列、$$2: 検索文字列
// (返り値) ##return: 見つかった位置(0オリジン)、-1:見つからなかった
//----------------------------------------------------------
strstr2:
##RC = -1;
$$Wk = $$1;
##Flg = 1;
##Size = 1;
if( ( ascii( $$2 ) & 0xff00 ) != 0 )
{
##Size = 2;
}
while( 1 )
{
##Pos = strstr( $$Wk, $$2 );
if( ##Pos == -1 )
{
break;
}
##RC = ##RC + ##Pos + ##Flg;
##Flg = ##Size;
$$Wk = rightstr( $$Wk, strlen( $$Wk ) - ##Pos - ##Size );
}
return ##RC;
// サンプルマクロ(ここまで)


[HMM0075A]

●浮動小数点数版秀丸との互換性

Q. 浮動小数点数バージョンの秀丸でマクロを実行すると、これまで通常の秀丸で動作していたマクロの一部が誤動作するのですが、互換性が無いのでしょうか?。

A. 浮動小数点数バージョンの秀丸は、秀丸マクロの数値型変数に、浮動小数点数を格納できるようにしたものです。
マクロの文法は、数値 (リテラル) の書き方以外は100%互換がありますが、
  1. 浮動小数点数版のほうが扱える数値の範囲が広い(小数も使える、大きい/小さい値を使える)ので、通常版の数値の仕様におさまらない場合があります。
  2. 通常版の秀丸の仕様である、数値型変数に整数しか入らないことを前提としたコーディングをしているマクロは、誤動作する可能性があります。

前者は比較的単純な話で、例えば、
#i = 1.5 ;
というのは浮動小数点数版では正常なコーディングですが、通常版ではエラーになります。
また、通常版秀丸では、4 バイトの符号付き整数(-2147483647〜+2147483648) なので、極端に大きい/小さい値を扱っている場合、浮動小数点版では問題ないが通常版秀丸では値がおかしくなります。

後者の例としては、/ (除算)の演算結果を変数に格納すると、通常版秀丸では整数の商が入り、余りが切り捨てられます。しかし、浮動小数点数版秀丸では、小数まで含んだ解が入ります。
その除算の結果をもとに条件判定すると、通常版と浮動小数点数版とで動作が異なる場合が出てきます。

以下の例は、#space個の半角スペースを$spaceに格納する例です。単にループして半角スペースを1個ずつ足していくよりも、以下のようにしたほうが秀丸マクロでは実行速度が出ます。
以下のコーディングでは、通常版では正しく動作しますが、浮動小数点数版で動作させると、whileループが意図したよりも1回多く回ることになります。
例えば #space == 10 の場合、#space / 80 == 0 であり、whileループの中のコードは実行されないというのが意図している動作です。浮動小数点数版では、#space / 80 == 0.125 であるため、whileループの中のコードが1回実行されてしまいます。

$space = "";
#sp1 = #space / 80;
#sp2 = #space % 80;
while (#sp1 > 0) {
$space = $space + $space80;
#sp1 = #sp1 - 1;
}
$space = $space + leftstr($space80, #sp2);

通常版も浮動小数点数版も同様に動作させるための方法は、意図している動作とロジックの関係で、必ずしも一概にはいえませんが、この例の場合、while文を

while (#sp1 >= 1) {
と変更することで、通常版も浮動小数点数版でも同様に動作するようになります。
あるいは、常に整数の商を得るため、
#sp1 = (#space - (#space % 80)) / 80;
としてもよいでしょう。

[HMM0076A]

●重複行の削除

Q. 重複行の削除はできませんか?。

A. 1 行の長さが改行を含め (半角で) 8191 文字以内なら下記のマクロで可能です。

//------------------ uniq.mac -------------------------------------
disabledraw;
gofiletop;
while(1){
selectline;
$$line = gettext(seltopx,seltopy,selendx,selendy);
if($$line == $$bline){
selectline;
delete;
}
else movetolineno 1,lineno + 1;
if(lineno == linecount2) break;
$$bline = $$line;
}
enabledraw;
endmacro;


目次に戻る