last updated:2022/12/06
秀丸エディタのマクロの中でも、応用的な機能の中には、2進数の概念やビット演算を使用する事があります。
例えば、以下の物があります。
C言語など、他の言語でこれらの概念や演算子を理解されている方はまだしも、初めての方はとっつきにくい部分があります。この章では、ビット演算のしくみと秀丸マクロでの使い方について説明します。
秀丸マクロで使えるビット演算子は以下の3種類があります。
& | ビット毎のAND |
| | ビット毎のOR |
^ | ビット毎のXOR |
と言われて、分かったという方は、以下の説明は多分必要ないでしょう。「ANDってどういうこと?」「ビット毎って何?」と思われる方もいるでしょう。ビット演算のしくみを説明するにあたって、まず関連の深い「2進数」「16進数」について説明します。その後、ビット演算子の意味と使い方について説明していきます。
10進数とは、0〜9の数字を1桁として表す数値の表現方法を指します。同様に考えれば、2進数とは、0〜1の数字を1桁として表す数値の表現です。
2進数は、一般にコンピュータで数値を表す時の基本となる表記方法です。スイッチの ON と OFF をそれぞれ 1と0に見立て、そのスイッチを複数集めることで、大きな値の桁も表します。
[例] 10進数、2進数、16進数の対応表。
10進数 | 2進数 | 16進数 |
---|---|---|
0 | 0 | 0 |
1 | 1 | 1 |
2 | 10 | 2 |
3 | 11 | 3 |
4 | 100 | 4 |
5 | 101 | 5 |
6 | 110 | 6 |
7 | 111 | 7 |
8 | 1000 | 8 |
9 | 1001 | 9 |
10 | 1010 | A |
11 | 1011 | B |
12 | 1100 | C |
13 | 1101 | D |
14 | 1110 | E |
15 | 1111 | F |
16 | 10000 | 10 |
10進数では 1の桁 10の桁 100の桁 …と続きますが、言い換えると 100の桁 101の桁 102の桁 …となります。
2進数では 20の桁 21の桁 22の桁 …と続きます。
2進数4桁(10進数でいえば0〜15)を1桁にまとめた数字の表現が16進数になります。
秀丸マクロでは、2進数を直接記述する方法は有りませんので、10進数か16進数のどちらかの表記を使うことになります。
秀丸マクロ(および一般にC言語)では、16進数の数字には頭に 0x という文字を付け、10進数でいう10〜15の数値をあらわす文字として A〜F を割り当てます。(半角文字を使用、大文字/小文字を区別しません)
10進数で11の値を、16進数で記述し変数に代入する。
#a = 0x0b;
もちろん、これは以下のように書くのと同じ意味です。
#a = 11;
秀丸エディタの側から見ると、どちらの方法で記述しても値としては同じであるため、結果は変わりません。逆にいえば、16進数表記は、ビット演算を行う場合に、コードを書く側の人間が、コードが理解しやすくなって便利な記述方法であるとも言えます。
ビットとは、2進数ではその1桁に相当します。 2進数8桁(16進数2桁)の単位をバイトといい、10進数では0〜255の範囲を表すことができます。
次にビット演算の概念を説明します。
AND、OR、XORは、それぞれ以下の結果になります。
AND(&)
両方とも1の場合だけ結果として1が返り、その他の場合は0になります。
1 AND 1 = 1
1 AND 0 = 0
0 AND 1 = 0
0 AND 0 = 0
OR(|)
少なくともどちらかが1の場合に結果として1が返り、両方とも0の場合は0になります。
1 OR 1 = 1
1 OR 0 = 1
0 OR 1 = 1
0 OR 0 = 0
XOR(^)
両方のビットが異なる場合にだけ結果として1が返り、その他の場合は0になります。
1 XOR 1 = 0
1 XOR 0 = 1
0 XOR 1 = 1
0 XOR 0 = 0
では、実際に秀丸マクロのビット演算子を使って確認してみましょう。以下のマクロを実行して、ダイアログに表示される演算結果を見てください。
#a = 1 & 1;
#b = 1 & 0;
#c = 0 & 1;
#d = 0 & 0;
message "1 AND 1 = " + str(#a);
message "1 AND 0 = " + str(#b);
message "0 AND 1 = " + str(#c);
message "0 AND 0 = " + str(#d);
#e = 1 | 1;
#f = 1 | 0;
#g = 0 | 1;
#h = 0 | 0;
message "1 OR 1 = " + str(#e);
message "1 OR 0 = " + str(#f);
message "0 OR 1 = " + str(#g);
message "0 OR 0 = " + str(#h);
#i = 1 ^ 1;
#j = 1 ^ 0;
#k = 0 ^ 1;
#l = 0 ^ 0;
message "1 XOR 1 = " + str(#i);
message "1 XOR 0 = " + str(#j);
message "0 XOR 1 = " + str(#k);
message "0 XOR 0 = " + str(#l);
冒頭で、 &, | , ^ は「ビット毎の」と書きましたが、複数ビットからなる値同士を計算するとビット毎に演算が行われます。いくつか例を見てみましょう。
2進数 | 16進数 | 10進数 | |
---|---|---|---|
10110110 | B6 | 182 | |
AND) | 10001000 | 88 | 136 |
|
|||
10000000 | 80 | 128 |
2進数 | 16進数 | 10進数 | |
---|---|---|---|
10110110 | B6 | 182 | |
OR) | 10001000 | 88 | 136 |
|
|||
10111110 | BE | 190 |
2進数 | 16進数 | 10進数 | |
---|---|---|---|
10110110 | B6 | 182 | |
XOR) | 10001000 | 88 | 136 |
|
|||
00111110 | 3E | 62 |
これを実際に秀丸マクロで記述すると以下のようになります。
#a = 0xb6 & 0x88;
#b = 0xb6 | 0x88;
#c = 0xb6 ^ 0x88;
message "0xb6 AND 0x88 = " + str(#a);
message "0xb6 OR 0x88 = " + str(#b);
message "0xb6 XOR 0x88 = " + str(#c);
これらの演算子を使って何ができるか。
これらの演算子を利用して、秀丸マクロの中では16進数の値(文字コード等)の分類ができたり、フラグの値として使用される値の一部ビットを操作したりできます。
AND演算を使うと、マスキング(=任意のビットを0にした値を出力)ができます。 0にしたいビットを0に、元の値を残したいビットを1にした値を作成してAND演算することで実現できます。
ANDで(2進数における)任意の桁が0か1かを調べる。
調べたい桁だけを1にし、それ以外を0にした数(この値のことをマスクなどともいいます)とAND演算して、結果がマスクと等しければ1で、等しくなければ0であると判ります。
2進数 | 16進数 | 10進数 | |
---|---|---|---|
00011110 | 1E | 30 | |
AND) | 00001000 | 08 | 8 |
|
|||
00001000 | 08 | 8 |
複数の桁を一気に判定することもできます。
2進数 | 16進数 | 10進数 | |
---|---|---|---|
00110110 | 36 | 54 | |
AND) | 10010000 | 90 | 144 |
|
|||
00010000 | 10 | 16 |
OR演算を使うと、任意のビットを1に変更できます。
1にしたいビットを1に、元の値を残したいビットを0にした値を作成してOR演算することで実現できます。
20ビット〜23ビット(下位4ビット)を1にしたい場合。
2進数 | 16進数 | 10進数 | |
---|---|---|---|
10110110 | B6 | 182 | |
OR) | 00001111 | 0F | 15 |
|
|||
10111111 | BF | 191 |
XOR演算を使うと、任意のビットの値を反転できます。
2進数 | 16進数 | 10進数 | |
---|---|---|---|
10110110 | B6 | 182 | |
XOR) | 11111111 | FF | 255 |
|
|||
01001001 | 49 | 73 |
encode(charset)キーワード は、ビット0〜5までが文字コードを示し、ビット6〜7が改行コードを示します。
$encode[0]="新規作成直後";
$encode[1]="Shift-JIS";
$encode[2]="Unicode";
$encode[3]="EUC";
$encode[4]="JIS";
$encode[5]="UTF-7";
$encode[6]="UTF-8";
$encode[7]="Unicode (Big-Endian)";
$encode[8]="欧文";
$encode[9]="簡体字中国語";
$encode[10]="繁体字中国語";
$encode[11]="韓国語";
$encode[12]="韓国語(Johab)";
$encode[13]="中央ヨーロッパ言語";
$encode[14]="バルト語";
$encode[15]="ギリシャ語";
$encode[16]="キリル言語";
$encode[17]="シンボル";
$encode[18]="トルコ語";
$encode[19]="ヘブライ語";
$encode[20]="アラビア語";
$encode[21]="タイ語";
$encode[22]="ベトナム語";
$encode[23]="Macintosh";
$encode[24]="OEM/DOS";
$encode[25]="その他";
$encode[26]="バイナリモード";
$encode[27]="UTF-32";
$encode[28]="UTF-32 (Big-Endian)";
$newline[0]="CR+LF";
$newline[1]="LF";
$newline[2]="CR";
$newline[3]="CR+LF";
// encode の構造(上位2ビットが改行、下位6ビットがエンコードを示す)
// 76543210 ビット順
// XXxxxxxx 2進数
// エンコード部分のみ切り出し
// XXxxxxxx:encodeキーワードの値
//AND) 00111111:0x3F
//--------------
// 00xxxxxx:文字コード
#encode = encode & 0x3F;
// 改行部分のみ切り出し
// XXxxxxxx:encodeキーワードの値
//AND) 11000000:0xC0
//--------------
// XX000000:改行コード
// ついでにビットシフト代わりの割り算(6ビット右シフト)
#newline = (encode & 0xC0) / 64;
message "エンコードは「" + $encode[#encode] + "」です。\n" +
"改行コードは「" + $newline[#newline] + "」です。";
endmacro;
.hilightファイル内で、強調表示部分の設定を表示する。
//カーソルのある行を取り込む
$line = gettext2(0, lineno, linelen2, lineno);
#pos = strstr($line, ",");
if(#pos == -1) endmacro;
//値のみ切り出し
#check = val(leftstr($line, #pos));
//表示方法のみ切り出し
#hilifgt1 = #check & ((0x08 | 0x10 | 0x20) ^ 0xFFFFFFFF);
//検索方法のみ切り出し
#hilifgt2 = #check & (0x08 | 0x10 | 0x20);
//結果を初期化
$hilight = "";
//表示方法(値)をチェック
if (#hilifgt1 == 0x001) $hilight = "強調1";
else if(#hilifgt1 == 0x041) $hilight = "強調2";
else if(#hilifgt1 == 0x081) $hilight = "強調3";
else if(#hilifgt1 == 0x0C1) $hilight = "強調4";
else if((#hilifgt1 == 0x101) || (#hilifgt1 == 0x103)) $hilight = "強調5";
else if((#hilifgt1 == 0x141) || (#hilifgt1 == 0x143)) $hilight = "強調6";
else if((#hilifgt1 == 0x181) || (#hilifgt1 == 0x183)) $hilight = "強調7";
else if((#hilifgt1 == 0x1C1) || (#hilifgt1 == 0x1C3)) $hilight = "強調8";
else if(#hilifgt1 == 0x005) $hilight = "行の強調1";
else if(#hilifgt1 == 0x045) $hilight = "行の強調2";
else if(#hilifgt1 == 0x085) $hilight = "行の強調3";
else if(#hilifgt1 == 0x0C5) $hilight = "行の強調4";
else if(#hilifgt1 == 0x003) $hilight = "特に強調1";
else if(#hilifgt1 == 0x043) $hilight = "特に強調2";
else if(#hilifgt1 == 0x083) $hilight = "特に強調3";
else if(#hilifgt1 == 0x0C3) $hilight = "特に強調4";
//検索方法(ビット)をチェック
if((#hilifgt2 & 0x008) == 0x008) $hilight = $hilight + ",大文字/小文字を区別しない";
if((#hilifgt2 & 0x010) == 0x010) $hilight = $hilight + ",正規表現";
if((#hilifgt2 & 0x020) == 0x020) $hilight = $hilight + ",単語";
//結果を表示
message $hilight;
endmacro;
searchoption を取得し、必要な設定を行い検索する。
//検索オプション取得
#SEARCH_OPT = searchoption;
//「大文字/小文字の区別」がOFFなら有効にする。
if((#SEARCH_OPT & 0x00000002) != 0x00000002) #SEARCH_OPT = #SEARCH_OPT | 0x00000002;
//「置換かどうか」置換ならOFFにする。
if((#SEARCH_OPT & 0x00000004) == 0x00000004) #SEARCH_OPT = #SEARCH_OPT ^ 0x00000004;
setsearch searchbuffer, #SEARCH_OPT;
existfile関数は、第2引数に「1」を指定すると、ファイル属性を取得できます。その戻り値をチェックし、フォルダ(ディレクトリ)か判定しています。
#ATTRIBUTE_READONLY = 0x00000001;
#ATTRIBUTE_HIDDEN = 0x00000002;
#ATTRIBUTE_SYSTEM = 0x00000004;
#ATTRIBUTE_DIRECTORY = 0x00000010;
#ATTRIBUTE_ARCHIVE = 0x00000020;
$CHECK = macrodir;
#FILE_ATTRIBUTE = existfile($CHECK, 1);
if((#FILE_ATTRIBUTE & #ATTRIBUTE_DIRECTORY) == #ATTRIBUTE_DIRECTORY){
message "[" + $CHECK + "]はフォルダです。";
}
endmacro;