利用者:Sukemaru

提供: MeryWiki
ナビゲーションに移動 検索に移動

目次



マクロライブラリに投稿したマクロ[編集]

「テキスト操作補助」 カテゴリ[編集]

インデント/逆インデント (last modified: 2019/12/01) ※ ブックマークを保持
  • 引用符/コメント ※ポップアップメニュー (last modified: 2019/04/07)  ※行頭の文字列操作マクロ「引用の追加」の増補改訂版
  • カッコで囲う ※ポップアップメニュー (last modified: 2019/04/07)
カッコで囲う (簡易版 ポップアップメニューなし)
引用符を追加/削除  ※"二重引用符" の追加/削除トグル




「ファイル操作補助」 カテゴリ[編集]

「他(右側/左側)のタブを閉じる」 などを追加 ※ポップアップメニュー版あり
エンコード指定で読み直し・読み取り専用属性の変更・編集モードの変更・プロパティを開く・さいごに閉じたファイルを開く・etc.



「変換・ソート・整形」 カテゴリ[編集]

+ 改造版「ToDoリストモード[1]」 (added: 2019/05/06)



>> 目次へ

「検索・置換」 カテゴリ[編集]

+ おまけマクロ「次の文字列を検索前の文字列を検索 (検索オプションをリセット&強調なし)」他
+ 機能強化版「文字数・行数・バイト数・ヒット件数(選択文字列)」 ※イベントマクロ (last modified: 2019/12/03)


検索ジャンプ 【include版】



「プログラミング補助」 カテゴリ[編集]

  • 行コメント (last modified: 2019/11/10) ※コメントマーク付け外し ブックマークを保持


「実験的マクロ・練習マクロなど」 カテゴリ[編集]

サンプルコード: 「特定の条件で縦書きモードに切りかえる」(※ ver 2.6.5 - 2.7.5 用)
+「位置を復帰/保存」 (include版)



ブックマークを復元



「その他」 カテゴリ[編集]

サンプルコード: 「Begin/EndUndoGroup() メソッドを使えるのは ver 2.7.0 以降」
サンプルコード: 「すべての論理行をポップアップメニューに表示する」





外部サイトに投稿したマクロ[編集]



>> 目次へ

組み込み用コード・小関数[編集]

メインコードの途中に短い 関数 を置く場合は、最初の呼び出しコードより前に変数(関数式)として定義しておいてもよい。

{
  var hoge = "hogehoge";
  // function 宣言で定義された関数は、宣言された位置より前からでも呼び出せる
  document.selection.Text = HogeFuga( hoge );

  // 関数宣言は参照可能なスコープ内のどの位置に置いてもよい
  function HogeFuga( str ) {
    return str.replace( /hoge/ig, "fuga" );
  }
}

ならば、以下のような記述でも同じ意味 (ただし、関数式の場合は、最初に呼び出す文よりも前に定義しておくこと)。

// 関数式は最初に呼び出されるよりも前に定義すること
var HogeFuga = function( str ) {
  return str.replace( /hoge/ig, "fuga" );
};
var hoge = "hogehoge";

document.selection.Text = HogeFuga( hoge );


メタ記号をエスケープする[編集]

任意の文字列を正規表現変数 RegExp() におさめる前などにエスケープ(退避修飾)する。

  • 正規表現のメタ記号のみ をエスケープする方法。
※ ref. 『正規表現 - JavaScript | MDN
/**
 * 関数 RegQuote( str )
 * 
 * 正規表現のメタ記号をすべてエスケープ(退避修飾)する
 */

function RegQuote( str ) {
  return str.replace( /[.*+?^=!:${}()|[\]\/\\]/g, "\\$&" ); 
}


  • または、記述の簡単な方法。
※ ref. 『JavaScript/正規表現 - Wikibooks
/**
 * 関数 Quote( str )
 * 
 * 半角アルファベットと半角数字以外の文字を
 * すべてエスケープして返す
 */

function Quote( str ) {
  return str.replace( /\W/g, "\\$&" );
}

// function Quote( str ) {
//   return str.replace( /\W/g, function( $0 ) {
//     return "\\" + $0;
//   } );
// }
※ JavaScript において $& は "マッチした部分文字列全体" を意味する JavaScript ネイティブの 特殊変数
置換関数 function() の引数がひとつの場合、その引数は $& と同じ意味になるので、上の関数で $0 と記述していることに特別な意味はない(tmpstrchr など任意の文字列でもよい)。
※ 後述、関数の「呼び出しコスト」 の項に書いているように、上出のふたつの Quote( str ) 関数の処理速度にはちがいが生じる。



数値を3ケタ区切り(カンマ区切り)にする[編集]

/**
 * 関数 SeparateNum( num )
 * 
 * 数値を3ケタごとにカンマ区切りした文字列にして返す
 * 引数(推奨):整数値
 * ※ 小数点以下が4ケタ以上の場合、小数点以下もケタ区切りされてしまう
 */

function SeparateNum( num ) {
  return num.toString().replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
}


小数、または半角数字を含む文字列の場合は

/**
 * 関数 SeparateNum2( num )
 * 
 * 数値を3ケタごとにカンマ区切りした文字列にして返す
 * 引数:任意の数値(を含む文字列)
 * ※ 小数点以下はケタ区切りしない
 */

function SeparateNum2( num ) {
  var num = ( num === 0 || ! num ) ? "0" : num;
  var a = num.toString().split( /\b/ );
  for ( var i = 0, len = a.length; i < len; i ++ ) {
    if ( a[i] == "." ) { i ++; continue; }
    a[i] = a[i].replace( /(\d)(?=(?:\d{3})+(?!\d))/g, "$1," );
  }
  return a.join( "" );
}


数値を小数点以下3ケタの固定長にする[編集]

/**
 * 関数 NumFix( num )
 * 
 * 数値を小数点以下3ケタの固定長小数(文字列)にして返す
 * 引数(推奨):任意の数値(または数字のみの文字列)
 */

function NumFix( num ) {
  if ( typeof num == "number" ) {
    return num.toFixed( 3 );
  }
  else if ( /^-?\d+(?:\.\d+)?$/.test( num.toString() ) ) {
    return Number( num ).toFixed( 3 );
  }
  else {
    return num;
  }
}

// 対象が数値( Number 型)であれば toFixed() だけでよい
// num = num.toFixed( 3 );


>> 目次へ

数値をケタ埋め(ゼロ埋め)する[編集]

※ 引数の型に応じた関数を使用する。

/**
 * 関数 Pad( num )
 * 
 * 半角1ケタの数値を0埋めして2ケタの文字列で返す
 * ※ 引数は「正の整数値」のみ
 */

function Pad( num ) {
  return num < 10 ? "0" + num : num;
}
/**
 * 関数 Pad2( str )
 * 
 * 文字列中に含まれる半角1ケタの数値を0埋めして2ケタにした文字列で返す
 * ※ 引数は「文字列値」のみ
 */

function Pad2( str ) {
  return str.replace( /[0-9]+/g , function( num ) {
    return num.length < 2 ? "0" + num : num
  } );
}
/**
 * 関数 NumPad2( val )
 * 
 * 半角1ケタの数字を0埋めして2ケタにした文字列で返す
 */

function NumPad2( val ) {
  return val.toString().replace( /[0-9]+/g, function( num ) {
    return num.length < 2 ? "0" + num : num;
  } );
}


任意の文字列のくりかえしで埋める[編集]

※ Windows XP 用

/**
 * 関数 Repeat( str, count )
 * 
 * String.prototype.repeat( count ) の代用
 */

function Repeat( str, count ) {
  var ret = "";
  for ( var i = 0; i < count; i ++ ) {
    ret += str;
  }
  return ret;
}


ストップウォッチ・タイマー[編集]

// 計測開始		※ ソースコードの先頭付近におくこと
var start = new Date();

// 任意のコードを実行
{ ; }

// ステータスバーに処理時間を表示
Status = ( ( new Date() - start ) / 1000 ).toFixed( 3 ) + " 秒";


Mery のバージョン情報[編集]

/**
 * Mery のバージョン情報
 */
var meryVersion = /([^\\]+$)/.exec( editor.FullName )[1] + " "
                + editor.Version;
Status = meryVersion;


JavaScript (JScript) エンジンのバージョン情報[編集]

※ ref. 『ScriptEngine 関数 (JScript) | Microsoft Docs

/**
 * JavaScript (JScript) エンジンのバージョン情報
 */
var engine = ScriptEngine() + " ";
           + ScriptEngineMajorVersion() + ".";
           + ScriptEngineMinorVersion() + ".";
           + ScriptEngineBuildVersion();
Status = engine;


>> 目次へ

マクロ覚え書き[編集]

リンク集[編集]


MeryWikiHaijin Boys Online


外部サイト




拙作マクロはポップアップメニューを利用するものが多いので、Tips はその方面の内容に偏ってしまいますが、以下、個人的に注意していることや気付いたことなど。


アイコン化したマクロ[編集]

通常、フォーカスがアウトプットバーやアウトラインペイン、検索/置換ダイアログにあると、ポップアップメニューやショートカットキーからマクロを起動することはできない。
しかし、Document オブジェクトのかわりに Editor.ActiveDocument で記述したマクロであれば、エディタ領域にフォーカスがない場合でもツールバーアイコンやマクロメニューからマクロを起動できる。

※ ただし、アクティブなタブ以外を操作・編集するマクロにおいては Editor.Documents.Item( dd ) などのような記述が必要。

マクロをツールバー/マクロバーから使用するために アイコン を作ったり、マクロバーにアイコンを詰め込むために 試行錯誤 したりも…。

イベントマクロ[編集]

イベントマクロ を実行できる "イベント" の種類
赤字 は遅延時間を設定できるイベント
フォーカスを受け取った時 エディタのウインドウがアクティブになったとき。
・「オプション」 などモーダルなダイアログからの復帰時には発動しない
Editor.ActiveDocument == Document
フォーカスを失った時 エディタのウインドウがアクティブでなくなったとき。
・「検索」 「置換」 ダイアログを開いたときにも発動する…
Editor.ActiveDocument != Document
ファイルを開いた時 複数ファイルをまとめて開いたときは、すべて開いたあとに1回だけ。
・複数ファイルをまとめて開いたときには、さいごのタブにしか作用しない
ファイルを保存した時 複数ファイルをまとめて保存したときは、すべて保存したあとに1回だけ。
更新状態が変更された時 「保存済み」 状態から 「未保存*」 状態になったときに発動した。
カーソルが移動した時 キャレット位置が動いたとき。
遅延 を大きく設定しないと、すごくジャマ
スクロールした時 エディタウインドウをスクロールしたとき。
・マウスホイール操作やスクロールバーの操作、
 PgUp / PgDn / Home / End キーなどでスクロールさせたとき
・文字入力中や、矢印キーなどでのキャレット移動にともなうスクロールでは発動しない
選択範囲が変更された時 範囲選択したときと、選択範囲を解除したとき。
遅延 を大きく設定しないと、ドラッグ操作や Shift+矢印キーで範囲選択するときにジャマ
テキストが変更された時 入力・削除・置換などの編集操作をしたとき。
遅延 を大きく設定しないと、すごくジャマ
文字が挿入された時 文字数が増えたとき?
・選択範囲文字列の [ Ctrl+ドラッグ ] による複製や、
 クリップボードからのペースト、
 マクロの Document.Write( "hoge" )
 Document.Selection.Text = "hoge" では発動しないようだった
遅延 を大きく設定しないと、すごくジャマ
編集モードが変更された時 編集モードを変更したとき。
・マクロで編集モードを変更したときも
アクティブな文書が変更された時 別のタブをアクティブにした後に発動。
・タブを閉じた後や、新規タブを開いたときにも
文書を閉じた時 複数のタブをまとめて閉じたときは、すべて閉じたあとに1回だけ。
・最後のタブが閉じてエディタウインドウが終了する場合は発動しない
タブを移動した時 タブをドラッグ&ドロップ操作で動かしたとき。
・左側のタブを閉じて右側のタブが動いた場合には発動しない
アイドル状態になった時 (不明)
ファイルを保存する前 ファイルを保存する前。


※ イベントマクロ であっても、ショートカットキーなどで任意のタイミングに強制的に実行できる。
※ イベントマクロでない「マクロA」のコードでファイルを 開く または 閉じる をおこない、それ以降にも「マクロA」のコードが続いている場合は、ファイルを開いた時/閉じた時の「イベントマクロB」は発動しないことがある。


  • sukemaru の Mery では、「バイト数」マクロと「文字数・行数・ヒット件数(選択文字列)」マクロの機能を統合したマクロに「ファイルを開いた時」「選択範囲が変更された時」「テキストが変更された時」「文字が挿入された時」「アクティブな文書が変更された時」イベントを設定している(太字 のイベントには遅延時間を 1 秒に設定。 ロースペックな PC ゆえ、一定以上の長さのファイル/タブにおいては機能を制限してある)。
    遅延時間が短すぎると、"文字列や選択範囲を変更するような他のマクロの実行後に、そのマクロからのステータスメッセージが読めなくなるから"、という意味もある。
  • また、「編集モードの自動選択 (include版)」マクロを「ファイルを開いた時」「文書を閉じた時」イベントに、補助マクロ を「ファイルを保存した時」イベントに設定して、それなりに按配よく運用できている。
    include ライブラリ を利用して、複数のファイルを開いたときにも、それぞれのタブにたいして編集モードの変更や書き換え禁止を適用できるようにしてある)



>> 目次へ

ポップアップメニュー[編集]

sukemaru の環境では、メニューに表示するアイテムが 5000 件とか 10000 件とかを超えるとポップアップメニューが表示されず(エラーメッセージも表示されず)にマクロが終了してしまうことがある…。
検索ジャンプ」マクロの include 版で発生するのだが、ポップアップメニューを表示する直前にステータスバーに表示すべき情報を ClipboardData.SetData( Status ); でコピーしておくと、

ヒット数: 21,525 件 ( 4 件目 ) ・ 21,525 行 ( 4 行目 ) / 全体の行数: 61,001 行  [ 12. 906 秒 ]

のようにデータが残ったので、前処理段階でコケたのではなくポップアップメニューの描画のさいにコケていたようだ。
また、11 万行の文書から空行を検索したとき、ステータスバーに以下のメッセージを表示して

一致: 27,814 行 / 空白行数: 27,849 行 / 全体の行数: 111,186 行  [ 6. 485 秒 ]

ポップアップメニューも表示されたが、実際に表示されていたアイテム数は 6000 件台で、20000 件以上のアイテムは表示されずにスポイルされてしまっていたということもあった。

以下の単純なコードでアイテム 10000 件のポップアップメニューを表示させようとしても、4000 件ぐらい(4000 前後で不定)までしか表示されない…。

var m = CreatePopupMenu();
for ( var i = 1; i <= 10000; i ++ ) {
  m.Add( "" + i, i );
}
var r = m.Track( mePosMouse );


環境依存の不具合かもしれないが、はて…?

オプションフラグ[編集]

PopupMenu.Add() メソッド の第三引数 Flags : int を数値化すると

meMenuChecked	= 1
meMenuGrayed	= 2
meMenuChecked + meMenuGrayed = 3
meMenuSeparator	= 4

となるので、真偽値が true=1false=0 で評価されることを利用して、真偽値を返す変数や条件式を代入することができる(ただし Number 型に変換する必要がある → 算術演算子「+」をつけるなど)。

var menu = CreatePopupMenu();
var hoge = true;
var fuga = false;

menu.Add( "Hoge", 1, + hoge );		// "+" を付けて数値化すると meMenuChecked
menu.Add( "Fuga", 2, !fuga * 2 );	// (!fuga = 1) *2 なので meMenuGrayed
var num = menu.Track( mePosMouse );
※ オプションフラグ meMenuGrayed を使用して条件付きで特定の項目をグレーアウトするだけでなく、menu.Add( ... ); の行を if() 文 で囲むなどすれば、状況に応じたメニュー項目だけを表示させることもできる。



アクセラレータ[編集]

ポップアップメニューのラベルの文字列に「半角アンパサンド記号 & + 半角英数字 (またはアスキー記号)」を付記することで、アクセラレータ(アクセスキー)を設定することができる。
ラベルの先頭に連番数字などがある場合は、アンパサンド記号を付加することで、数字をアクセラレータにするとよい。
そのさい、Shift キー付きでの入力が必要な記号は Shift キーなしで入力可能なキーのラベルと同一視される (e.g. 「&#」で # 記号をアクセラレータに指定した場合、JIS 配列のキーボードでは 3 キーがアクセラレータになる)。

  • & 記号でアクセラレータ化する文字の位置は限定されないが、最初の & 記号のうしろの文字がアクセラレータになる( … とおもわれる ← ポップアップメニュー内で「下線つきで表示される文字」と一致しないことがある)。
  • 全角文字はアクセラレータにできない。
  • ラベル文字列に含まれる & 記号はすべてエスケープされてしまい、ポップアップメニューには表示されなくなるので、ラベルに & 記号を表示させたいときは、&& のように二重に記述する必要がある。
    → 不特定の文字列をラベルにする場合は、あらかじめ String.replace( /&/g, "&&" ) と記述するとよい。
&& で表示される & 記号は、アクセラレータにならない。
  • 同じキーが重複してアクセラレータに指定されていると、そのキーを押した場合、アイテム間をトグル移動する(その場合は Enter キーで決定する)。
    → アイテム数が多くなるメニューの場合、menu.Add( "キャンセル & ", 0 ); という行を 10 件とか 20 件ごとに挿入すると、スペースキーでポップアップメニュー内をスクロールさせることができる。
※「& 」(半角アンパサンド+半角空白) で半角スペースをアクセラレータに指定したアイテムは、Space キーがアクセスキーになる。
/* アクセラレータを付加する */

var menu = CreatePopupMenu();
var piyo = "LOVE & PEACE & ...";

menu.Add( "アイテム1(&1)", 1 );		// [1] キーがアクセラレータ
menu.Add( "アイテム&2", 2 );			// [2] キーがアクセラレータ
menu.Add( "0&3 アイテム3", 3 );		// [3] キーがアクセラレータ
menu.Add( "&Hello &World &4", 4 );	// [H] キーがアクセラレータ
menu.Add( piyo.replace( /&/g, "&&" ) + "(&5)", 5 );	// [5] キーがアクセラレータ
menu.Add( piyo + "(&6)", 6 );		// スペースキーがアクセラレータ
menu.Add( "※※※※", 0, meMenuSeparator );	// meMenuSeparator があると第一引数の文字列は無視される
menu.Add( "キャンセル & ", 0 );		// スペースキーがアクセラレータ

// 5つめのアイテムは "LOVE & PEACE & ..." と表示されるが
// 6つめのアイテムは "LOVE  PEACE   ..." と表示される 

// ※ 6つめのアイテムと最後のアイテムでアクセラレータが重複している

var ret = menu.Track( 0 );
/* 10 行ごとに「キャンセル」項目を挿入し、スペースキーでスクロール可能にする */

var arr = document.Text.split( "\n" );
var menu = CreatePopupMenu();

for ( var i = 0; i < arr.length; i ++ ) {
  if ( i > 0 && i % 10 == 0 ) {
    menu.Add( "", 0, meMenuSeparator );
    menu.Add( "キャンセル & ", 0 );
    menu.Add( "", 0, meMenuSeparator );
  }
  menu.Add( arr[i].slice( 0, 30 ), i + 1 );
}

var y = menu.Track( 0 );
if ( y ) {
  document.selection.SetActivePoint( mePosLogical, 1, y );
}


ラベルの整形[編集]

  • 基本的にポップアップメニュー(警告・確認ダイアログなどもだが)は UI フォントで表示されるので、文字列が英数字の羅列の場合には読みづらい ( …と個人的に感じている)。
文書内の文字列など不特定の文字列をラベル化する「検索ジャンプ」や「ブックマークジャンプ」、「クリップボード履歴メニュー」マクロでは、読みづらい半角アルファベットや記号を全角化させるなどしている。
/**
 * ポップアップメニューに表示するラベルを整形する
 * 
 * ※ 不要な置換については .replace( ... ) の行を 削除/コメントアウト してよい
 * 
 * ・行頭空白を除去
 * ・空白文字を圧縮:				→「›」(U+203A) に置換
 * ・文字数を切り詰め( String.slice メソッド )
 * ・改行記号を可視化:			→「↲」(U+21B2) または「⏎」(U+23CE) に置換
 * ・削られてしまう「&」を補完
 * ・「¥」(U+005C) を「∖」(U+2216) に置換
 * ・特殊な空白文字を豆腐に置換:	→「⊠」(U+22A0) または「▯」(U+25AF) 
 * ・判読しづらい ascii 記号  !"%'(),.:;@[]`{|}  を全角に置換
 * ・「a-z」を全角に置換
 */

var y = document.selection.GetActivePointY( mePosLogical )	// 行番号
var str = document.GetLine( y, 0 );		// 行の文字列
var menuWidth = 55;						// 切り捨ての閾値
var reg = /[\u00A0\u1680\u180e\u2000-\u200A\u2028\u2029\u202F\u205F\uFEFF]/g;

var menuKey = str.replace( /^[\t  ]+/, "" )
                 .replace( /(?:\t|[ ]{3,}|[ ]{2,})+/g, " › " )
                 .slice( 0, menuWidth + 1 )
                 .replace( /\r?\n/g, " ↲ " )
                 .replace( /[&]/g, "&&" )
                 .replace( /[\\]/g, "∖" )
                 .replace( reg, "▯" )
                 .replace( /[!"%'(),.:;@\[\]`a-z{|}]/g,
                   function( tmp ) {
                     return String.fromCharCode( tmp.charCodeAt( 0 ) + 0xFEE0 )
                   } );

// 文字数を切り詰めた場合は「 ...」を付加
menuKey += ( str.length > menuWidth ) ? " ..." : "";


// 文字列の先頭に行番号(連番)を付加する

// パターン➀: アクセラレータつきの番号(左端揃え)を付加
var num = "&" + y;
menuKey = num + ": " + menuKey;

// パターン➁: 番号(左端揃え)の 末尾1桁 をアクセラレータにするなら
var num = String( y ).replace( /\d$/, "&$&" );
menuKey = num + ": " + menuKey;

// パターン➂: 連番が多いときは「空白文字でケタ埋め (右端揃え)」するとよい
// 例: EN SPACE「 」(U+2002) でケタ埋めして、末尾1桁 をアクセラレータにする
var numWidth = String( d.GetLines( 0 ) ).length;
var num = ( "      " + y ).slice( - numWidth ).replace( /\d$/, "&$&" );
menuKey = num + ": " + menuKey;
※ このコードでは色々と unicode 文字を使用しているので、マクロの JS ファイルは UTF-8 などの形式で保存しなければならない。


  • また、「マクロライブラリに投稿したマクロ」の節の画像リンク(サムネイル)のように、タブインデントや連番のケタ埋め、サブメニューの活用などの工夫で、ポップアップメニューの体裁はある程度自分好みにカスタマイズできる。



ステータスバーの表示[編集]

ポップアップメニュー表示のさいにステータスバーに任意の文字列を表示する場合は、 PopupMenu.Track() の行の直前に Status = "hoge"; を記述する。
PopupMenu.Track() が発動した時点でエディタウインドウ本体は停止するので、直後に Status = "hoge"; を記述しても、ポップアップメニューの項目を選択するかメニューをキャンセルするまで表示されない。

// e.g. ポップアップメニュー表示までのマクロの処理時間をステータス表示させる

// 計測開始		※ ソースコードの先頭付近におくこと
var start = new Date();

// 文書の各論理行を配列におさめ、ポップアップメニュー項目に
var ay = document.selection.GetActivePointY( mePosLogical );
var lineArray = document.Text.split( "\n" );
var menu = CreatePopupMenu();
for ( var i = 0, y, flag; i < lineArray.length; i ++ ) {
  y = i + 1;
  flag = ( y == ay ) ? meMenuChecked : 0;
  menu.Add( y + ":  " + lineArray[i].slice( 0, 50 ), y, flag );
}

// ステータスバーに処理時間を表示
Status = ( ( new Date() - start ) / 1000 ).toFixed( 3 ) + " 秒";

// ポップアップメニューを表示
var yy = menu.Track( mePosMouse );

// 選択した行に移動する
if ( yy ) {
  document.selection.SetActivePoint( mePosLogical, 1, yy, false );
}


※ 順番が逆になると、ステータスはポップアップメニュー項目を選択(またはキャンセル)するまで表示されない。
※ ポップアップメニューにかぎらず、警告 (Alert)確認 (Confirm)入力 (Prompt) ダイアログなどモーダルなポップアップウインドウを表示させる場合も、同様に Status = "hoge"; を先に記述する必要がある。
※ Mery メインウインドウのメニューバー項目のような、マウスホバーで動的にステータス表示を変更させる制御はできない。



>> 目次へ

配列からポップアップメニューを生成[編集]

for 文 などの ループ処理 によって配列からポップアップメニューのアイテムを生成する場合に、PopupMenu.Add() メソッド の第二引数 Id (※通常は 1 ~ )と配列のアイテムのインデックス [ i ] の値(※通常は 0 ~ )を一致させたいときは、配列の先頭にダミーまたは空の要素を置いておき、ループ処理の開始インデックスを 1 にする。

var a = new Array( "" );				// 先頭に空のダミー要素を入れておく
a.push( "あああ" );
a.push( "いいい" );
a.push( "ううう" );
// a = [ "", "あああ", "いいい", "ううう" ] となる

var menuA = CreatePopupMenu();
for ( var i = 1; i < a.length; i ++ ) {	// 開始値を 1 にすると
  menuA.Add( a[i], i );					// Id を ( i + 1 ) にする必要がない
}
var num = menuA.Track( mePosMouse );

// c.f. 空要素なしの配列 [ "あああ", "いいい", "ううう" ] をループ処理する場合
var b = [ "あああ", "いいい", "ううう" ];
var menuB = CreatePopupMenu();
for ( var i = 0; i < b.length; i ++ ) {
  menuB.Add( b[i], i + 1 );				// Id を 1 ~ にするには ( i + 1 )
}


サブメニュー[編集]

サブメニューを組みこむ場合、通常はそれぞれの PopupMenu オブジェクトをあらかじめ宣言しておくものだが、PopupMenu.AddPopup() メソッド 内の第二引数で定義することもできる。
PopupMenu.Add() メソッド が大量に並んでいる項目群の一部をサブメニュー化して整理したくなったときなどに、サブメニューオブジェクトの宣言行を用意しなくて済むので便利である。
サブメニューを多重に含むコードの場合、字下げ(インデント)を活用することで、メニューの階層構造を把握しやすくできる。

var mainMenu = CreatePopupMenu();
mainMenu.Add( "アイテム1", 1 );
mainMenu.AddPopup( "サブメニュー1", subMenu1 = CreatePopupMenu() );
  subMenu1.Add( "アイテム2", 2 );
  subMenu1.AddPopup( "サブメニュー2", subMenu2 = CreatePopupMenu() );
    subMenu2.Add( "アイテム3", 3 );

var r = mainMenu.Track( 0 );
Alert( ret > 0 ? mainMenu.GetText( r ) : "キャンセル" );


  • 配列やオブジェクトからポップアップメニューの生成をするときにサブメニューを利用する場合、あらかじめサブメニューのラベルや各要素の振り分け方が決まっていれば難しいことはないが、要素が不定数の配列やオブジェクトを複数のサブメニューに振り分けるのは簡単ではない…。
→ 組み込み関数「ポップアップメニューを手軽に扱う」や「階層化マクロメニュー」マクロなどのソースコードを参考にして自力でコードを組むか、組み込み関数「ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する」で一定数ごとにサブメニュー項目を自動生成して要素を放り込むしかない。


以下は、自動分割サブメニューのサンプルコード。

// ポップアップメニューの項目にする任意の配列を用意する
var itemArray = [];
// ※ アイテムとして 1 ~ 100 の数値を放り込んでおく
for ( var i = 0; i < 100; i ++ ) {
  itemArray.push( i + 1 );
}
var len = itemArray.length;

var mainMenu = CreatePopupMenu();
var subMenu,  id;

// 配列からポップアップメニューを生成する
for ( var i = 0, j = 1; i < len; i ++ ) {
  // アイテムを 20 件ずつ分割収容するサブメニューを自動生成する
  if ( i % 20 == 0 ) {
    // ※ ループ処理 20 回ごとに subMenu を新しいサブメニュー項目として更新する
    subMenu = CreatePopupMenu();
    // 「サブメニュー 1」からの連番つき定型文字列
    mainMenu.AddPopup( "サブメニュー " + ( j ++ ), subMenu );
  }

  // アイテムをサブメニューに収容する
  id = i + 1;
  // 「アイテム 1」からの連番つき定型文字列
  subMenu.Add( "アイテム " + id, id );
}

// ポップアップメニューを表示
var r = mainMenu.Track( 0 );
Alert( r > 0 ? mainMenu.GetText( r ) : "キャンセル" );

※ 組み込み関数「ポップアップメニューを「n*十件ずつ」のサブメニューに自動分割する」のソースコードでは、サブメニューオブジェクト専用の配列 smArray を用意して smArray.push( CreatePopupMenu() ); → menu.AddPopup( label, smArray[ smId ] ); としているが、上のサンプルコードのようにループ処理内で subMenu = CreatePopupMenu(); を使いまわしするだけでも新規のサブメニューアイテムを生成できるようだ。

サブメニュー内のすべてのアイテムが無効(グレーアウト)になる条件でも、サブメニュー見出しを無効化することはできないので、サブメニュー見出しが表示されなくなるように(またはグレーアウトされるように) PopupMenu.AddPopup() 周りを if() 文 で囲うしかない(※ メニューの階層構造が複雑な場合に、ソースコードが見づらくなってしまうが…)。
// e.g. 編集モードが Text ならサブメニューを表示する
// ※ Text 以外ならグレーアウトさせた "サブメニュー" アイテムを表示

var menu1 = CreatePopupMenu();
var menu2 = CreatePopupMenu();

if ( document.Mode == "Text" ) {
  menu1.AddPopup( "サブメニュー", menu2 );
    menu2.Add( "アイテム2", 2 );
} else {
  menu1.Add( "サブメニュー", 0, meMenuGrayed );
}
menu1.Add( "アイテム1", 1 );

var r = menu1.Track( mePosMouse );


また、上出の「自動分割サブメニュー」の組み込み関数を制作するさい、チェックつきアイテムを含むサブメニュー見出しにもチェックを付けられるようにしたかったが、これも無理だった。
→ サブメニューオブジェクトを AddPopup() する前に孫アイテムを Add() しておき、チェックつきアイテムを含むかどうかの条件文でサブメニューオブジェクトのラベルを生成(サブメニューラベルの先頭に "*\t" や "" などを付加)してから AddPopup() することはできるが、 meMenuChecked とおなじチェックマークをつけられるわけではないので、コードが煩雑になるわりにあまり報われない努力となる…。



マクロの動作設定を変更可能にする[編集]

拙作マクロは、ポップアップメニューを使うものにかぎらず動作設定用の項目が多い。
ポップアップメニューマクロでないものは、通常、頻繁に動作設定を弄る必要はないが、sukemaru 好みの動作方式は一般的嗜好と合致しないであろうことから公開用のマクロにするにあたってカスタマイズ可能な「設定項目 (変数)」ににして調整しなおすことが多い…。

ポップアップメニューマクロであれば、メニュー項目から動作設定をカスタマイズできるようにコーディングすることができる。

  • まず、masme 氏の「行並べ替え」や「連番を挿入」マクロのように、do ... while() 文 によるループを利用して、動作設定の既定値を何度も書き換えながらポップアップメニューを再描画する方法がある。
動作設定の変更内容はマクロの完了時に破棄されてしまうので、同じマクロを連続して利用することが多いならば、マクロメニューの 編集 コマンドからソースコードを開いて、初期設定項目(変数)の既定値を書き換えておくとよい。
これらにおいては、include ライブラリ の IO クラス(IO.js)の関数メソッド Serialize() Deserialize() を利用して、ポップアップメニュー内の「設定変更」サブメニューから変更した 設定値を外部ファイル(JSON ファイル)に保持 できるようにしている。
カスタマイズしながら実行するのも、カスタマイズした動作設定を維持したままでままで再実行するのも容易にはなったが、コードが煩雑になって他のマクロに流用しづらくなってしまっている…。
※ 非 include 版では、「設定変更」サブメニューや masme 氏のマクロのような処理コードは入れず、動作設定の変更方法はソースコードの変数の値の書き換えのみとしている。



GetKeyState.exe の活用[編集]

pizz 氏作成の「GetKeyState.exe(キー状態取得実行ファイル)」を使うと、マクロ実行(開始)時の修飾キーの押し下げ状態でポップアップメニューに表示する項目を変化させたり、メニュー内のアイテムを選択(クリック)するときの修飾キーの押し下げ状態で実行するコマンドを変化させることができる。
マクロ開始時に仕込むとショートカットキーの割りあて方が制限されたり、メニュー表示までにタイムラグが生じてしまうこともあるが、アイテム選択後のコマンド実行時に仕込めばあまり問題にならない。
※ ただし、Mery のポップアップメニューは Alt キーでキャンセルされてしまうので、コマンド実行時に仕込めるのは CtrlShift キーにかぎられる。

ref. GetKeyState.exe の実装例: サンプルコード3



>> 目次へ

配列[編集]

var arr1 = [];
arr1[arr1.length] = "hoge";
arr1[arr1.length] = "fuga";
arr1[arr1.length] = "piyo";
... ;

個人的な所感であるが、配列の要素を羅列して定義するさいに、上のような書き方は好きではない。以下のような書き方のほうが、スッキリしていてよい。

var arr2 = [];
arr2.push( "Hoge" );
arr2.push( "Fuga" );
arr2.push( "Piyo" );
... ;
var arr3 = [
  "HogeHoge",
  "FugaFuga",
  "PiyoPiyo",
  ...
];
// ※ カンマの位置は、前でも後ろでも


複数行の論理行を範囲選択(末尾改行を含まない)[編集]

文字列操作のマクロでしばしば必要になる処理。
※ 行番号のクリックやドラッグによる行単位の範囲選択をしたときや Selection.SelectLine() のあとなど、選択範囲末尾の改行(次行の先頭)を除外するときに必要。

※ 以下のふたつのコードは、左下(行頭位置)から右上に矩形選択した状態から実行したときの結果が異なる。

var s = document.selection;
// もとの選択範囲の座標を取得
var ty = s.GetTopPointY( mePosLogical );
var by = s.GetBottomPointY( mePosLogical );
var bx = s.GetBottomPointX( mePosLogical );
// 選択範囲の末尾が行頭 x = 1 にあるときの調整
if ( bx == 1 && ty != by ) { by -= 1; }
// 論理行全体を範囲選択(さいごの末尾改行 \n をふくめない)
s.SetActivePoint( mePosLogical, 1, by );
s.EndOfLine( false, mePosLogical );
s.SetAnchorPoint( mePosLogical, 1, ty );
// または masme 氏作成の「コメントマーク付け外し」マクロより
// ※ 左下(行頭位置)から右上に矩形選択した場合も考慮したコード
var s = document.selection;
var ty = s.GetTopPointY( mePosLogical );
var by = s.GetBottomPointY( mePosLogical );
var bx = s.GetBottomPointX( mePosLogical );
var br = ( s.Text.match( /\n/g ) || [] ).length;
if ( bx === 1 && by - ty === br && br ) { by --; }
s.SetActivePoint( mePosLogical, 1, by );
s.EndOfLine( false, mePosLogical );
s.SetAnchorPoint( mePosLogical, 1, ty );
ref. Mery 公式フォーラム 『マクロについてアドバイスお願いします



選択範囲の 先頭位置/末尾位置[編集]

選択範囲の 開始(キャレットなし)/終了(キャレットあり) の位置は Selection.GetAnchorPos()Selection.GetActivePos() とで取得できるが、先頭/末尾 の位置はそれらをもとにして前後関係を割りだす必要がある。
GetTopPos()GetBottomPos() というメソッドはない。

var ancPos, actPos, topPos, endPos;

ancPos = document.selection.GetAnchorPos();	// 選択開始位置
actPos = document.selection.GetActivePos();	// 選択終了位置(キャレット位置)

topPos = Math.min( ancPos, actPos );		// 選択範囲の先頭位置(左・上)
endPos = Math.max( ancPos, actPos );		// 選択範囲の末尾位置(右・下)

// topPos と endPos の取得は以下のような記述方法でも可
topPos = ( ancPos < actPos ) ? ancPos : actPos;
endPos = ( ancPos < actPos ) ? actPos : ancPos;


変換・挿入した文字列を範囲選択するとき[編集]

var str = "hoge";
document.Write( str );	// または document.selection.text = str;

のあとで文字列 hoge を範囲選択したい場合は、document.selection.CharLeft( str.length, true ); ではなく

// キャレットは選択範囲の末尾位置
document.selection.SetAnchorPos( document.selection.GetActivePos() - str.length );

// または(キャレットは選択範囲の先頭位置)
document.selectionSetActivePos( document.selection.GetActivePos() - str.length, true );

と記述すること。

Selection.CharLeft( str.length, true ) の場合、文字列 str が「折り返し」にかかってしまったときに想定どおりの選択範囲にならない。

ref. Mery 公式フォーラム 『"折り返し表示" での CharRight( document.selection.Text.length - 1 ) について



>> 目次へ

Collapse() メソッド とキャレット位置[編集]

Selection.Collapse() メソッド で引数 meCollapseEnd を指定した場合は

Selection.SetActivePos( Selection.GetActivePos() ) 

meCollapseStart を指定した場合は

Selection.SetActivePos( Selection.SetAnchorPos() )

と意味的には同じである。

※ 引数を省略した場合は meCollapseStart として動作する。
meCollapseStart / meCollapseEnd はそれぞれ「選択開始位置」と「選択終了位置 (キャレット位置)」を指し、「選択範囲の 先頭/末尾」ではない。
Selection.SelectLine()Selection.SelectWord() メソッドなどでの範囲選択では「キャレット位置=選択範囲の末尾」となり、Selection.Find()Selection.FindRepeat() メソッドでの範囲選択では「キャレット位置=選択範囲の先頭」なので、つづけて Collapse() メソッドを使用するときは注意が必要 (…というほどのことでもないか?)。

Find() メソッド と FindRepeat() メソッド の 定数[編集]

定数 の数値は

Alert( meFindNext );

のような1行マクロで調べることができる。

Find() メソッド
document.selection.Find() メソッド
指定のパターンを検索します。

 0: meFindPrevious		カーソル位置から前を検索します。
 1: meFindNext			カーソル位置から次を検索します。
 2: meFindReplaceCase		検索する単語の大文字と小文字を区別します。
 4: meFindReplaceOnlyWord	完全に一致する単語を検索します。
 8: meFindAround		文書の末尾まで検索したら先頭から検索を開始します。
16: meFindReplaceRegExp		正規表現で検索します。


「検索/置換」ダイアログのオプションフラグをすべて OFF にする方法 として
document.selection.Find( "", 0 );	// 空文字列の検索でオプションフラグを解除する
というコードを挟み込むという手がある(第二引数には 0 または 1 を指定する)。
ref. Mery 公式フォーラム 『空検索の動作、など
これは、マクロ実行時に「検索/置換」ダイアログが開かれていないときにかぎり、マクロ終了後の「検索/置換」ダイアログのオプション項目のチェック ON/OFF の状態にも引き継がれる(次回の「検索/置換」や「次/前を検索」「次/前の文字列を検索」コマンドなどにも引き継がれる)。
※ ただし、「終了したら閉じる」と、ベータ版 2.6.10 で追加された「インクリメンタルサーチ」のオプションフラグはマクロから解除することができない。
meFindReplaceOnlyWordmeFindReplaceRegExp は排他関係なので、同時に使用した場合 meFindReplaceRegExp は適用されるが meFindReplaceOnlyWord は無視される
(検索ダイアログで「正規表現」オプションを有効化したときに「単語のみ」オプションが無効になるのと同様)。


FindRepeat() メソッド
document.selection.FindRepeat() メソッド
前回検索した文字列を検索します。 

 0: meFindPrevious	カーソル位置から前を検索します。
 1: meFindNext		カーソル位置から次を検索します。
 2: meFindRepeatWord	選択範囲が空の場合はカーソル位置の単語を検索します。
FindRepeat() メソッドでは定数 meFindReplaceCasemeFindReplaceOnlyWord , meFindAround , meFindReplaceRegExp が使用できないが、 直前 の「検索/置換」コマンドや Find() / Replace() メソッドで使用したこれらのオプションのうち meFindReplaceRegExp 以外の三つの ON/OFF 状態が 継承 される。
よって、FindRepeat() メソッドで meFindReplaceCasemeFindReplaceOnlyWord , meFindAround を適用した検索をしたいばあいは、以下のように記述すればよい。
meFindReplaceRegExp があっても FindRepeat() の実行時には無視される。
// 1.空文字列の検索をして、任意のオプションフラグを設定(付加)する
document.selection.Find( "", meFindNext + meFindReplaceCase + meFindAround );

// 2.「前回検索した文字列を検索」または キャレット位置の単語で「次の文字列を検索」
document.selection.FindRepeat( meFindNext + meFindRepeatWord );

// -------------------------------------------------- //

// 3.最後にオプションフラグを解除しておきたいなら
document.selection.Find( "", 0 );
※ ➂ のコードを最後に使用した場合、「検索/置換」ダイアログのオプションフラグも解除される。


  • ちなみに、sukemaru は検索ダイアログの履歴に残るマクロや、検索ハイライトが残るマクロが好きではないので、なるべく
     を使わずに JavaScript ネイティブの [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf String.indexOf( searchValue, fromIndex ) メソッド] や [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace String.replace( regexp ) メソッド] で検索/置換を行なったり、 [[マクロリファレンス:Document インターフェイス#HighlightFind プロパティ|Document.HighlightFind = false]] で検索マーカーを消すなどする自作マクロが多い ([https://www.haijin-boys.com/software/mery/mery-2-6-0#3 自動マーカー] で背景色をハイライトする設定にしているから「検索ハイライト」はいらなくて…)。
    : [ [https://www.haijin-boys.com/software/mery/mery-tips#2 Ctrl+Shift+↑ / ↓] ] の機能も「[[次/前の文字列を検索・改]]」マクロに置きかえてしまったので、検索ダイアログを開くのは正規表現で検索するときぐらいかも。
    <br><br>
    
    === 文字列操作が空振りしたときは undo 履歴に残さない ===
    * 条件付きで文字列操作挿入置換などするマクロが空振りしたときに
    <source lang="javascript">
    // e.g. 選択範囲に「hoge」が含まれなければ置換しない
    var fuga = document.selection.Text.replace( /hoge/g, "fuga" );
    document.selection.Text = fuga;
    
上のようなコードの場合は undo 履歴に無駄に残ったり、文書に「未保存 *」のフラグが付加されたりする。
以下のように「文字列操作の前後で "変化なし" なら undo 履歴には残さない」記述にすると、変更行の強調表示 なども無用に付かなくなる。
// e.g. 選択範囲に「hoge」が含まれなければ置換しない
var st = document.selection.Text;
var piyo = st.replace( /hoge/g, "piyo" );

if ( st != piyo ) {
  document.selection.Text = piyo;
}


Document.Selection クラス の文字列操作メソッドの場合は、以下のように記述することで「変換なしなら undo 履歴を巻き戻し」できる。
// 変換前の文字列 と 保存済み/未保存 の状態を取得
var st = document.selection.Text;
var sv = document.Saved;

if ( st && ! document.ReadOnly ) {

  // 小文字に変換
  document.selection.ChangeCase( meCaseLowerCase );

  // 変換なしなら undo 履歴を巻き戻す
  if ( document.selection.Text == st ) {
    document.Undo();
    document.Saved = sv;
  }
}
※ ただし、厳密にいえば undo 履歴には残っているので、redo (やり直し: Ctrl+Y) することができる。



>> 目次へ

スクロール位置の調整[編集]

キャレットをジャンプさせた後のスクロール位置とキャレット位置は、移動先の行(表示座標での行番号)がエディタの表示領域の高さに収まるかどうかとジャンプ方向によるので安定的ではない(スクロールマージンの考慮も必要)。

以下のコードは、ジャンプ後にエディタの表示領域がスクロールした場合に、キャレットが表示領域の 先頭位置(window.ScrollY) になるように調整するもの。

var s = Document.Selection;
var ax = s.GetActivePointX( mePosLogical );		// キャレット位置の X
var ay = s.GetActivePointY( mePosLogical );		// キャレット位置の Y
var sy = ScrollY;	// エディタ表示領域の先頭行(物理行番号+スクロールマージン)

// 下方向に10行(論理行)ジャンプ
s.SetActivePoint( mePosLogical, ax, ay + 10 );

// スクロールしないならそのまま / スクロールするならキャレットは表示領域の先頭に
ScrollY = ( ScrollY == sy )
            ? sy
            : s.GetActivePointY( mePosView );

// つねにジャンプ先の行が先頭になるようスクロールさせるなら
// ScrollY = s.GetActivePointY( mePosView );

// ※ ScrollY プロパティに値を代入するときは物理座標(表示行)の行番号で

※ スクロールマージンは ベータ版 2.7.0 より「オプション」ダイアログの「スクロール」のページ内で変更できるようになっている。[2]

Window オブジェクト[編集]

通常はソースコード内で Window オブジェクト を明示的に記述する必要はないが、バージョンチェック の節の「例4」のように 実際に記述する場合には Window ではなく window でないと宣言されていない変数・オブジェクトあつかいのエラーになる。

DocumentSelectionAlert など他の主要なプロパティは「大文字/小文字/頭文字のみ大文字」の区別なしに同一のプロパティとしてあつかわれる。

カレントディレクトリ[編集]

カレントディレクトリ(作業フォルダ)は、Mery を起動したときに決定され、一定ではない。
記述の都合上で相対パスを利用するために特定のカレントディレクトリを指定するマクロもあるが、「あえて流動的なカレントディレクトリを利用する」ようなコードが続く場合は、カレントディレクトリを書きもどす必要がある。

var fso = new ActiveXObject( "Scripting.FileSystemObject" );
var wshShell = new ActiveXObject( "WScript.Shell" );

var meryIni = Editor.FullName.replace( /exe$/, "ini" );

if ( fso.FileExists( meryIni ) ) {
  // メモ帳で Mery.ini を開く
  wshShell.Run( "notepad \"" + meryIni + "\"" );
}
else {
  // マクロ実行前の作業フォルダを保存
  var currentDir = wshShell.CurrentDirectory;

  // 相対パス解決のためにカレントディレクトリを設定	e.g. %AppData%\Mery
  wshShell.CurrentDirectory = wshShell.SpecialFolders( "APPDATA" ) + "\\Mery";
  wshShell.Run( "notepad " + "Mery.ini" );
  
  // マクロ実行前の作業フォルダを復帰
  wshShell.CurrentDirectory = currentDir;
}


※ マクロでカレントディレクトリを変更すると、実行中の Mery のプロセスの作業フォルダも変更されるため、あとから他のマクロを実行するさいのカレントディレクトリにも影響する。
→ システムの関連付けを利用してテキストファイルなどのダブルクリックから Mery を起動した場合、そのファイルの親フォルダが Mery のプロセスの作業フォルダとなり、Windows OS の仕様により Mery のプロセスを終了するまでそのフォルダはロックされた状態になる(フォルダの移動や削除ができなくなる)が、マクロでカレントディレクトリを変更するとフォルダのロックを解除できる。

動作要件としてのバージョンチェック[編集]

公開するマクロに Mery ベータ版で追加されたマクロ用プロパティ・定数を利用する場合は、マクロの動作要件として Mery 本体のバージョンをチェックするコードを入れておくのが無難である。

  • JavaScript には特定のプロパティがオブジェクト配下に定義されているかを調べる方法も色々とあるが、親オブジェクトのタイプやプロパティ・定数のタイプ、JavaScript(JScript)のバージョンによる互換性などへの考慮が必要になる。 [3][4][5]


  • 拙作の 組み込み関数 VersionCheck() を利用すれば、Mery のバージョン番号を指定して動作要件のチェックができる。
※ あらかじめ、プロパティや定数が導入された Mery のバージョン番号を調べておく必要がある( ← Mery.txt に記載されているはず)。
// ▼ ChangeCase() メソッドで定数 meCaseCapitalize を使えるのは ver 2.6.10 以降

if ( document.Selection.IsEmpty ) {
  document.selection.SelectLine();	// とりあえず行を範囲選択
}

// 例1. VersionCheck() 関数を利用する場合
if ( VersionCheck( "2.6.10" ) ) {
  // 「単語の最初の文字を大文字に変換」
  document.selection.ChangeCase( meCaseCapitalize );
}
else {
  // 「小文字に変換」
  document.selection.ChangeCase( meCaseLowerCase );
  Status = "小文字で許せ。";
}

function VersionCheck( versionStr ) {
  /* 関数のコードをコピペ */ ;
}

// -------------------------------------------------- //

// 例2. 定数が定義されているかを調べる場合
if ( typeof meCaseCapitalize == "number" ) {	// または meCaseCapitalize==3
  // 「単語の最初の文字を大文字に変換」
  document.selection.ChangeCase( meCaseCapitalize );
}
else {
  // ExecuteCommandByID() で「単語の最初の文字を大文字に変換」
  editor.ExecuteCommandByID( MEID_EDIT_CAPITALIZE = 2116 );
}
// ▼ BeginUndoGroup() メソッドを使えるのは ver 2.7.0 以降

// 例3. VersionCheck() 関数を利用する場合
if ( VersionCheck( "2.7.0" ) ) {
  BeginUndoGroup();
}

function VersionCheck( versionStr ) {
  /* 関数のコードをコピペ */ ;
}

// -------------------------------------------------- //

// 例4. メソッドが定義されているかを調べる場合
if ( "BeginUndoGroup" in window ) {
  BeginUndoGroup();
}


外部リソースのチェック[編集]

「include ライブラリ」や「GetKeyState.exe」のような外部リソースを必要とする前提のマクロでも、それらのリソースがない場合にもある程度マクロが動くようにコーディングすることができる。

  • include ライブラリ が必要なマクロの場合、ユーザー側が include ライブラリを正しく導入していることが要求される。
ユーザー側で include ライブラリが導入されていて、マクロ側で #include "include/IO.js" のようなプリプロセッサがソースコードの先頭で宣言されていれば問題ないのだが、include ライブラリが導入されていなくても、プリプロセッサを削除(コメントアウト)すればマクロがある程度動くようにコーディングすることもできる。
// #include "include/IO.js"

if ( typeof IO == "object" ) {
  /* IO.js がインクルードされているときの動作 */ ;
}
else {
  /* IO.js がインクルードされていないときの動作 */ ;
}


// あらかじめ変数 ctrl に 0 を代入しておく
var ctrl = 0;

// GetKeyState.exe のパスで実行ファイルの実在確認をする
var getKeyState = editor.FullName.replace( /[^\\]+$/i , "" )
                + "Macros\\GetKeyState.exe";
var fso = new ActiveXObject( "Scripting.FileSystemObject" );

if ( fso.FileExists( getKeyState ) ) {
  // GetKeyState.exe で Ctrl キーの押し下げ状態を取得する
  var wshShell = new ActiveXObject( "WScript.Shell" );
  ctrl = wshShell.Run( "\"" + getKeyState + "\" control", 0, true );
}

if ( ctrl == 1 ) {
  /* GetKeyState.exe があり、Ctrl キーが押されているとき */ ;
}
else {
  /* GetKeyState.exe がない、または Ctrl キーが押されていないとき */ ;
}


>> 目次へ

Mery.ini から設定値を取得する[編集]

include ライブラリ の MeryInfo クラス (MeryInfo.js) を利用して Mery.ini からいくつかの設定項目の値や状態を取得することはできるが、制約が非常に多い。

  • 取得できる項目がきわめて限定的である
  • 取得する項目が複数あると、その都度 Mery.ini 全体の読み込みが発生する(キャッシュ可)
  • Mery.exe のファイル名を変更 (e.g. Mery_hoge.exe) している場合、MeryInfo.js のコードを改変しないと Mery.ini (Mery_hoge.ini) のパスを得られず、設定値を取得できない。


拙作の 組み込み関数 GetIniOption()GetIniOption2() はこれらの制約を受けず、とくに後者は Mery.ini のすべての項目にアクセスして値を取得することができる。
ただし、制約がない代わりに組み込み関数自体のコードが長いことや、引数や戻り値が配列であることでコードが煩雑にならざるをえない( ⇔ 配列を使用することで、複数の項目を取得する場合でも Mery.ini ファイルの読み込みを1回におさえられる)。
IO.LoadFromFile() 関数で Mery.ini を読みこむ という方法もある。

また、Mery.ini 側の仕様として、

「オプション」など各種の設定ダイアログを [ OK ] ボタンで閉じたときか、
エディタウインドウを閉じたときにしか Mery.ini への書き込みがされないため、
メニュー項目/ツールバーアイコン/ショートカットキー で変更した設定内容は
Mery.ini に直ちに反映されない

という制約がある(Mery.ini の実体ファイルへの書き込み回数を減らすための仕様)。

エディタの表示状態をトグル切り替えするコマンド(縦書き、色の反転、全画面表示、etc. ...)については、マクロ用の標準メソッド/プロパティから「現在の表示状態」を取得する手段がなく、組み込み関数 GetIniOption2() で Mery.ini を読み込んでも、必ずしも「最新の設定状態」を取得できるわけではない…。

※ 「現在の表示状態」を取得してから ON/OFF を指定しての切り替えを行なうためには、include ライブラリの IO クラスを利用するなどして外部に Mery.ini とは別の設定ファイル (e.g. JSON ファイル) を用意し、切り替え実行のたびに設定ファイルを読み書きする必要がある。
ただし、この方法をとる場合は、外部ファイルに設定内容をあずける項目(コマンド)の切り替えについては必ずマクロ経由で行なわなければならず、デフォルトの メニュー項目/ツールバーアイコン/ショートカットキー による通常操作でその項目の状態の変更をすると、最新の設定状態(現在の表示状態)と外部ファイルが保持している設定内容とのあいだに齟齬が生じてしまう。

→ e.g. 「折り返しトグル切り替え」マクロ



外部ファイルにマクロの設定などを書き出す[編集]

マクロの設定情報を保存して次回の実行時にそれを参照して使いたい場合、include ライブラリ の IO クラス (IO.js) の IO.Serialize()IO.Deserialize() を利用するのがもっとも簡単な方法だとおもわれる。

※ ただし、マクロの実行ごとに外部ファイル(設定ファイル.JSON と include ライブラリの IO.js および json2.js)を読みこむことになるので、環境によってはマクロの動作のもたつきや エラー が生じてしまう可能性がある。

以下、「折り返しトグル切り替え」マクロを例に IO.Serialize() Deserialize() の利用方法の簡単な説明。

#include "include/IO.js"
  // \Macros\include\IO.js をインクルードする
  // ※ ソースコードの1行目に記述すること。

/* 【準備】 */
// ■ JSON のファイル名(この場合 折り返し.json)	※定義しなくてもよい
var jsonName = "折り返し";

// ➀ 書き出し内容として使う「オブジェクト」を用意する
var setting = {};

// ➁ 設定項目として使う「プロパティ」と「初期値」を定義する
setting.wrapMode = 0;
setting.count = 0;
  // ※ objectName.propertyName = value;
  //    value には数値以外(文字列、真偽値、配列など)も設定できる。

// または、以下のようにまとめてもよい ( ➀+➁ と意味は同じ)
var setting = { wrapMode: 0, count: 0 }
  // ※ {ブラケット} で囲う場合はコロンで結んで  propertyName : value  とする。
  //    複数のプロパティを列挙する場合はカンマ「,」で区切る。
  //    最後にセミコロン「;」をつけないこと。

/* 【JSON 読み込み】 */
// JSON ファイルに保存された設定値で上書きする
setting = IO.Deserialize( setting, jsonName );
  // ※ 第2引数 jsonName を省略した場合は、自動的に「マクロ.js」のベース名。
  //    初回起動で JSON ファイルがないときは初期値のまま。

/* 【動作コード】 */
// 折り返しモード切替
if ( setting.wrapMode == 2 ) {
  editor.ExecuteCommandByID( 2146 );	// 折り返さない
  setting.wrapMode = 0;
} else if ( setting.wrapMode == 0 ) {
  editor.ExecuteCommandByID( 2147 );	// 指定文字数で折り返し
  setting.wrapMode = 1;
} else {	// else if ( setting.wrapMode == 1 )
  editor.ExecuteCommandByID( 2148 );	// ウインドウの右端で折り返し
  setting.wrapMode = 2;
}

// 任意のプロパティを追加することもできる
setting.dateTime = new Date();			// 最終実行日時の記録

// マクロの実行回数を記録
setting.count += 1;
if ( setting.count % 100 == 0 ) {		// 100 回ごとにダイアログを表示
  var d = setting.dateTime;
  var dateTime = d.getFullYear() + "/" + ( d.getMonth() + 1 ) + "/" + d.getDate()
               + " " + d.toLocaleTimeString();
  var str = dateTime + "\n\n"
          + ScriptName + " マクロ実行 " + setting.count + " 回目!!";
  Alert( str );
}

/* 【JSON 書き込み】 */
// setting オブジェクトの変更内容を保存する
IO.Serialize( setting, jsonName );


関数の「呼び出しコスト」[編集]

ユーザー関数は、呼び出し元から参照可能な位置に記述すれば、ソースコードの任意の位置に配置することができる。
繰り返し何度も呼び出して使用する関数の場合に「呼び出しコスト」を気にする人もいるらしいが、Mery で使用するマクロ程度のソースコードであればあまり気にする必要はないようにおもわれる。

e.g. 半角英数字以外を「¥」でエスケープ処理する
※ あえて ループ処理 で1行ずつエスケープしてみる (@ロースペの XP ノート

/* 関数バージョン */

function Quote( str ) {
  return str.replace( /\W/g, "\\$&" );
}

// または
// var Quote = function( str ) {
//   return str.replace( /\W/g, "\\$&" );
// }

BeginUndoGroup();
var lines = document.GetLines( 0 );
for ( var i = 1, st, a = []; i <= lines; i ++ ) {
  st = Quote( document.GetLine( i, 0 ) );
  a.push( st );
}
document.Text = a.join( "\n" );


function Quote( str ) でも var Quote = function( str ) でも、約 9500 行の日本語テキスト(約 33 万文字)にたいして 1.1 秒台の処理時間がかかり有意な差はみられなかった。
関数を使用しない以下のようなベタ書きのコードの場合でも、ほぼ同じ程度の処理時間がかかった (@ロースペの XP ノート)。

/* 非関数バージョン */

BeginUndoGroup();
var lines = document.GetLines( 0 );
for ( var i = 1, st, a = []; i <= lines; i ++ ) {
  st = document.GetLine( i, 0 ).replace( /\W/g, "\\$&" );
  a.push( st );
}
document.Text = a.join( "\n" );


※ ループ文の中で関数を定義した場合は、やや遅くなって 1.3 秒台。

BeginUndoGroup();
var lines = document.GetLines( 0 );
for ( var i = 1, st, a = []; i <= lines; i ++ ) {
  function Quote( str ) {
    return str.replace( /\W/g, "\\$&" );
  }
  st = Quote( document.GetLine( i, 0 ) );
  a.push( st );
}
document.Text = a.join( "\n" );


※ 行ごとのループ処理ではなく、文書全体の 一括処理 にすると速くなる。
上とおなじ Quote() 関数を使用しての文書全体の一括処理でも…

function Quote( str ) {
  return str.replace( /\W/g, "\\$&" );
}

document.Text = Quote( document.Text );

関数を使用しないベタ書きの一括処理でも…

document.Text = document.Text.replace( /\W/g, "\\$&" );

…処理時間はほぼ同じで、約 0.7 ~ 0.8 秒だった。
現行 OS の Chakra エンジン (jscript9.dll) であれば約 20 倍 の速度が出るらしいので、数メガバイトとか数万行とかのよほど長大な文書の処理をする場合でもなければ、「関数の呼び出しコスト」を気にする必要はあまりなさそう。

それよりも、

  • 文字列操作や検索/置換にさいして、なるべくキャレットの移動をともなうメソッドを使用しない
※ できるだけ Mery 独自のメソッドよりも、代替可能な JavaScript の String オブジェクトのメソッド を変数内で使用する (Mery のマクロメソッドは「キー操作の記録と再生が一番の目的」なので、動作速度的に最適化されていないのかも)。
  • くりかえし何度も参照されるオブジェクトやプロパティは変数に格納する
e.g. Document.TextDocument.Selection.Textfor 文 での Array.length など。
  • 関数定義文で必要となる引数をすべて与えておき、関数スコープからグローバルスコープに変数の値を参照しに行かないで済むようにしておく

などで、ソースコードの最適化をはかるほうが良いはず。


※ ちなみに、Quote() 関数を以下のように記述した場合、上出のループ処理コードでの所要時間は 3 倍(3 秒台)。

function Quote( str ) {
  return str.replace( /\W/g, function( $0 ) {
    return "\\" + $0;
  } );
}

以下のような記述だと、ループ処理した場合の所要時間は 4 倍以上(4 ~ 5 秒台)になる。

function Quote( str ) {
  return str.replace( /\W/g, Escape );
}
function Escape( matched ) {
  return "\\" + matched;
}

…ループ処理から参照する関数のネストや二重参照は、ループ文内で関数を定義する場合以上に鬼門のようだ。
>> 目次へ

FileSystemObject と WScript.Shell でファイルパスを引数にするとき[編集]

引数として使用するファイルパス文字列に 半角空白 がふくまれている場合、

  • FileSystemObject ではパスをダブルクオートなどの 引用符で囲う必要がない
  • WScript.Shell などの WSH コードではパスをダブルクオートなどの 引用符で囲う必要がある


よって、WshShell.Run() コマンド などで不特定のパス(または任意のパス)を指定するときは WshShell.Run( "\"" + path + "\"" ) または 'WshShell.Run( '"' + path + '"' ) のように記述しておき、パスに半角空白がふくまれていてもエラーにならないように備えておくとよい。

// 半角空白を含むパス
var path = "C:\\Hoge hoge\\Fuga fuga\\Piyo piyo.txt";

var fso = new ActiveXObject( "Scripting.FileSystemObject" );
var wshShell = new ActiveXObject( "WScript.Shell" );

if ( fso.FileExists( path ) ) {			// 引用符で囲わないでよい
  wshShell.Run( "\"" + path + "\"" );	// 引用符で囲う必要がある
}


警告・確認ダイアログとステータスバーの使い分け[編集]

マクロからユーザーにメッセージを与える手段として 警告window.Alert)・確認window.Confirm)ダイアログと ステータスバーwindow.Status)への表示などがある(ほかに アウトプットバーOutputBar.Write)や ポップアップメニュー を使う方法もある)。

// e.g. ポップアップメニューを「ポップアップヒント」として使用する

if ( document.ReadOnly ) {
  var m = CreatePopupMenu();
  m.Add( "  このドキュメントは 書き換え禁止 です	& ", 0 );
  var r = m.Track( 1 );
}


基本的に、Mery のマクロで利用できるポップアップダイアログ(警告、確認)はどちらもサウンドをともない、ボタン操作で閉じるまで作業を中断させてしまうので、あえて作業を一時停止させる必要がある場面以外ではステータス表示を使用するのがよい。
※ ユーザー側がステータス表示を使用するイベントマクロなどを別途で導入していることを考慮すると、マクロの終了時になんらかのイベントが発生するマクロの場合、重要なメッセージはダイアログで出力させるか、マクロ内の動作設定用の変数で出力方法を選択できるようにしておくとなおよい。

また、Mery の Window クラスのメソッド・プロパティを使うほかにも、WSH の WshShell.Popup メソッド によるメッセージボックス利用することもできる。
ダイアログ内の左側のアイコンの種類や OK キャンセル はい いいえ などのボタンの種類をカスタマイズでき、指定時間の経過後に自動で閉じさせることもできるが、引数の指定や戻り値の処理が煩雑なので、 はい いいえ キャンセル の3ボタンが必要な場合でもなければお勧めはしない…。
※ アイコンなしにすれば、システムのサウンドなしでダイアログを表示できる。

>> 目次へ

その他、拙作マクロについて[編集]

Kuro 氏の 「引用を追加」マクロのカスタマイズ をきっかけとしてマクロの改造に手を染め、 マクロのアイコン化のためにアイコンを量産 していくうちにマクロの自作も始めて、マクロ制作のための補助的マクロの自作とか「タマゴ? ニワトリ?」状態になったりしています。
マウス派 として Mery を便利に扱えるようにするつもりでマクロを作っていますが、マニアックな個人的要求(欲求)を自己解決していくうちに Mery の外観 が本来の姿からかけ離れてしまっているという…。

  • sukemaru の Mery 運用環境はロースペックの Windows XP sp3 (32bit), JScript 5.8.20587 のノート PC (CPU: Atom 1.7GHz, 1 コア, 2 スレッド) です。
※ 制作したマクロの動作テストは、この XP 機でしかおこなっていません。
※ マクロの動作テストに使用している Mery のバージョンは、"最新のベータ版" (および "最新の正式版" ver. 2.6.7 ) のみです。 基本的に ver 2.6.7 以降のバージョンで動作するように作成していますが、ver 2.6.6 以前のバージョンでの利用を想定していません( ver 2.6.6 以下での動作確認はしていません)。
※ とくに「実験的マクロ・練習マクロ」カテゴリに投稿した【自家用】/【実験】マクロにおいては、よその環境を考慮した動作テストをしていません。
※ マクロの動作速度のテストは 青空文庫 からダウンロードした『吾輩は猫である』のルビを削除して1文ごとに改行させたテキストファイル(約 33 万文字/約 9500 行)でおこなっています。 1 メガバイト超のファイルでのテストはしていません ( ロースペ PC なので 2000 行を超えるあたりから動作速度が気になりだすのですが… [6])。
※ ZIP 版の Mery でマクロを作成・運用しているので、インストーラ版では正しく動作しないマクロがあるかもしれません。
  • 開発環境が Windows XP なので、拙作マクロは基本的に JavaScript(JScript)マクロです。
※ 変数はすべて var で宣言し、JScript 5.8 の環境で実行できるようにコーディングしています。
  • Mery のオプション設定で「行の表示方法=論理座標 (論理行)」の状態で運用する前提でマクロを作っています。 公開しているマクロでは、「表示座標 (表示行)」ベースで Mery を運用している場合でも利用できるように設定項目(変数)を設けるか「行の表示方法」を自動判定するコードを追加していますが、動作が不完全になったり処理がおそくなったりすることがあります。
※「表示座標 (表示行)」ベースでの動作テストはほとんどしていません。
  • ソースコード内ではしばしば unicode 文字を使用していますので、マクロの JS ファイルは UTF-8 形式で保存する前提となっています。
  • ソースコード内の変数名の検索などで「検索ジャンプ」マクロを利用しやすいように(個人的にタグジャンプ系のマクロに馴染めないので)、マクロのコードには半角空白を多用しています。
  • 基本的に、変数名は頭文字が小文字の camelCase に、関数名は頭文字が大文字の TitleCase にしてあります。


  • include ライブラリ」(作成: ks 氏) を利用する【include 版】と利用しない【通常版】とがあるマクロでは、include 版を優先的にメンテ・更新しています(←自家用)。
  • 外部実行ファイル「GetKeyState.exe」(作成: pizz 氏) の導入が必要なものもあります。[7]
  • ポップアップメニューマクロの「設定変更サブメニュー」など、複数のマクロで共通の自作関数を使用しているものがありますが、当面は「include ライブラリ」のような外部ファイルにまとめる予定なしです。
∴ すでに公開しているマクロが多いこと、公開用と自家用とでコードの内容がちがうマクロが複数あること、それぞれのマクロごとに自作関数のコードに改変をくわえていることなどの理由で、もはや関数・クラスを統一しなおして更新メンテするのが困難。
∴ 「include ライブラリ」のように独自クラスでまとめたものをインクルードして利用するよりも、必要な関数だけをソースコード内にコピペして使用するほうが、マクロの処理速度的には僅かながらも有利?(な気がする… @ロースペ XP)。


→ 念のため確認してみたら、やはり差は僅かだった。

※「include ライブラリ」の MeryInfo.js と IO.js をインクルード したマクロで Mery.ini ( 31 万文字超/約 5600 行、約 320 kB ) から「行の表示方法 (LineColumnView キー)」を取得すると、平均 0.125 秒。
#include "include/IO.js"
#include "include/MeryInfo.js"

var start = new Date();
// Mery.ini のテキストデータを読みこむ
var iniText = IO.LoadFromFile( MeryInfo.GetIniPath(), "utf-8" );
// LineColumnView キーの値を検索する
var lineColumnView = + /^LineColumnView=(\d)$/m.exec( iniText )[1];

Alert( "行の表示方法: " + ( lineColumnView ? "表示行" : "論理行" )
     + "\n\n" + ( ( new Date() - start ) / 1000 ).toFixed( 3 ) + " 秒" );


組み込み関数 GetIniOption2() を利用したマクロで「行の表示方法」を取得すると、平均 0.095 秒。
var start = new Date();
// 関数の戻り値 iniOption[0][2] が LineColumnView キーの値
var iniOption = GetIniOption2( [[ "General", "LineColumnView" ]] );

Alert( "行の表示方法: " + ( iniOption[0][2] ? "表示行" : "論理行" )
     + "\n\n" + ( ( new Date() - start ) / 1000 ).toFixed( 3 ) + " 秒" );

// ---------- ▼ 組み込み関数 ココから ▼ ----------
function GetIniOption2( keyArray ) {
  /* ~ 省略 ~ */
  // https://www.haijin-boys.com/wiki/Mery.iniのオプション値を取得#ソースコード_2
}
// ---------- ▲ 組み込み関数 ココまで ▲ ----------
GetIniOption2() 関数は、IO.LoadFromFile()MeryInfo.GetIniPath() のコードを翻案して作ったものなので、Mery.ini のパスを解決して ADODB.Stream で読みこむ 処理の部分はほぼ同じ。 Mery.ini のテキストデータから LineColumnView キーの値を検索する方法は異なるが、その部分は「include ライブラリ」を使用したコードの RegExp.exec( str ) メソッド のほうが速いはず。
※ GetIniOption2() 関数は String.search( regexp ) メソッド と、String.indexOf( searchValue, fromIndex ) メソッド ×3回でキーの値を取得する。
… とはいえど、「include ライブラリ」は多種多様な各クラス同士でのプロパティ(関数)の相互参照により高度に効率化されていて、おいそれとアレンジできない部分がたくさんあるため、素直にインクルードして利用するほうがよいのかも。



>> 目次へ

投稿した構文ファイル[編集]


ReplaceStr.txt / ImageViewURLReplace.dat / URLExec.dat / command.dat に対応
bregonig の正規表現のハイライト可 (基本的に onigmo の正規表現にも利用可)
※ 収録しなかった正規表現タグ (文字・文字種の変数など) があるので、リンク先ページ末尾の注記を参照のこと
MediaWiki 用構文ファイル
Mery の MSY 構文ファイル用
マクロの JS ファイル(JScript)用
JavaScript 用構文ファイル/入力補完用辞書/スペルチェック用辞書/おまけマクロ を同梱
※ Web 開発向けのキーワードは未収録


ref. Mery 公式フォーラム 『 デフォルトの構文定義の拡充について



>> 目次へ

スクショ[編集]


マクロバーのアイコン化

マクロバー (1段目) にアイコンを詰めこむための sukemaru の試行錯誤の遍歴... [8][9]

  • 共通
システム環境: Windows XP 32bit SP3 (Classic テーマ)
ウインドウサイズ (幅): 約 970 px
アイコンサイズ: 中 (24px)
アイコン:マテリアルデザインっぽいアイコン
標準ツールバー (2段目) のアイコン数: 28 コ


マクロバーのアイコン数 28 コ、ラベルなし、セパレータあり( #begingroup=3 )
Ver. 2.8.0

マクロバーのアイコン数 22 コ半、ラベルなし、余白あり( #title="" )
※ 3段目は外部ツールバー (アイコン 30 コ)
Ver. 2.7.8

  • Ver. 2.7.4 まで(2019/05/05)
マクロバーのアイテム数 16 件、ラベルあり(#title="hoge" の文字数を切りつめてやり繰り)
Ver. 2.7.4


  • 「マテリアルデザインっぽいアイコン」は、sukemaru の自作マクロと、sukemaru がマクロライブラリからダウンロードして利用しているマクロを対象として制作しています。
メニューバーの標準コマンド や、ショートカット設定/右クリックメニュー用コマンド、キーアサイン集 の小マクロをアイコン化できるように、『小マクロ集』としてまとめました。



おまけ[編集]

マーカー設定[編集]


正規表現でマーカーに登録するさいは、
ラベル |正規表現
のように並列演算子 | の左側に「題名+全角空白」、右側に正規表現としておくと、マーカーバーが見やすくなる(パフォーマンス的にはよくないかも)。

  • いわゆる「プログラミング用フォント」を導入していないので、ゼロ 0 と オー O や、イチ 1アイ I と エル l と バー | を区別できるよう、アイ と オー にマーカーを設定。
    円マーク ¥ (U+00A5) や 波ダーシ (U+301C) 他、見分けづらい文字も追加。

☑ 大文字小文字を区別  ☑ 正規表現
[OOII]|[¥∖╲〜☓×〇➀-➉]

※「半角数字」には、 [ オプション ] の [ 表示 ] 設定でカスタム文字色を設定。
※ 半角バーチカルバー (パイプ) | は、必要におうじて [ 編集モード ] の強調文字列に設定。
※ 小文字エル l は、出現頻度が高く、編集モードの登録単語にふくまれていることも多いので強調なし。


  • 特殊な空白文字用
    「MeiryoKe_Gothic」 フォントで通常の全角/半角空白と区別できない 特殊な空白文字 と、ゼロ幅空白文字

☑ 大文字小文字を区別  ☑ 正規表現
特殊な空白文字 |[\x{00A0}\x{2000}-\x{200A}\x{2028}\x{1680}\x{180E}]
ゼロ幅空白文字 |\g<blank>\g<chara>|(?<chara>[\n\s\S])(?<blank>[\x{200B}-\x{200E}\x{2029}\x{202C}\x{202F}\x{205F}\x{2062}\x{2063}\x{FEFF}])

※ 「MeiryoKe_Gothic」 フォントで文字化けして中黒 で表示されるものや、ゼロ幅結合子は含めていない。


  • /JavaScript の正規表現リテラル用/

☑ 大文字小文字を区別  ☑ 正規表現
正規表現リテラル |(?<=^|[{(\[= \t])\/(?![*+?|/)\]])[^\r\n\t]*\/[gmi]{0,3}(?=\s*(?:[.,:;})\]]|//|/\*|$))

※ ある程度の誤爆はやむなし。



スポンサーリンク