TrueとFalse を切り替える

提供:MeryWiki
2020年7月1日 (水) 23:40時点におけるSukemaru (トーク | 投稿記録)による版 (更新(マルチカーソル/複数選択範囲に対応))
ナビゲーションに移動 検索に移動

ダウンロード

※ Mery ver 3.0.1 以降の マルチカーソル/複数選択範囲 に対応


※ マルチカーソル/複数選択範囲 には 非対応


YESNO マクロ

選択範囲の文字列が True なら False に、False なら True に変換します。

ソースコード内に相互変換する単語のグループを登録して使用します。
選択範囲がないときにはキャレット位置の単語を自動選択するように設定できます。


  • TrueFalseYesNoはいいいえ2つの単語の相互変換 なら
[ "True", "False" ], 
[ "Yes", "No" ], 
[ "はい", "いいえ" ], 


  • ほげふがぴよほげ のような 3つ以上の単語を順々に変換 する場合も、列挙するだけです。
[ "ほげ", "ふが", "ぴよ" ], 
[ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ], 


  • 単語グループの登録は「頭文字が大文字」
[ "Hoge", "Fuga", "Piyo" ], 
[ "Hoge", "Fuga", "Piyo" ], 
だけであっても、
「小文字」だけの差分 hogefugapiyohogefugapiyo
「大文字」だけの差分 HOGEFUGAPIYOHOGEFUGAPIYO も変換できます。
※「小文字」だけのグループを登録した場合は「大文字」差分の変換もでき、「大文字」だけのグループを登録した場合は「小文字」差分の変換もできますが、どちらも「頭文字が大文字」の差分の変換はできません。 基本的に「頭文字が大文字」での登録をおすすめします。
※ 先頭以外にも大文字がある HoGe, FUga, PiyO などは変換しません (これらを変換させる場合は、別途で完全一致する単語グループが必要)。


  • 小文字や大文字の差分では変換させたくない グループを登録する場合は、グループの先頭に 0, を(引用符で囲わずに)置きます。
    以下の例では mozillaFIREFOX, ThunderBird は変換されません。
[ 0, "Mozilla", "Firefox", "Thunderbird" ], 
FireFoxThunderBird のように先頭以外にも大文字がある単語については、別途で完全一致する単語グループの登録が必要となります。


  • 「大文字」だけを除外したい 場合は、0, 付きの「頭文字」のグループと「小文字」のグループを登録します。
以下の登録例ではALPHABRAVOは変換されません。
[ 0, "Alpha", "Bravo", "Charlie", "Delta", "Echo" ],  
[ 0, "alpha", "bravo", "charlie", "delta", "echo" ],  
先頭の 0,「完全一致のみ」のフラグ になります( → 1false, true などを置くとエラー)。
"0", だと 半角数字の "文字列" になるのでグループ内の単語のひとつとして登録されます。


  • 左 → 右 方向には変換しても 右 → 左 (末尾から先頭)方向に変換させたくない場合 は、グループの最後に空の要素 , "" を置きます。
以下の登録例では Mery から NotepadTerapad には変換されません。
[ 0, "Notepad", "Mery", "" ],
[ "Terapad", "EmEditor", "gPad", "秀丸", "Mery", "" ],
※ グループの途中に空の要素 "" があると、 "" 以降の単語には変換されなくなります。



  • 2020/05/12: 仕様変更
※うえの登録例の [ ... , "Mery", "" ], のグループよりもうしろに
[ "Mery", "メリー", "羊" ], 
のようなグループがある場合は、NotepadMeryメリーMery のように変換されます。




  • 2020/05/12 - 2020/07/01: 機能追加
ダブルクリックでは一括選択できない「同一記号の繰り返し文字列」や「日付け文字列」を自動選択する機能、「今日の日付に変換」する機能を「拡張自動選択」マクロから移植しました(開発順序としては逆移植ですが)。
##########
※※※※※※※※
2020/07/01, 2020-7-1, 2020.7.1, 2020年7月1日
※ 単語の自動選択用の設定項目が有効 var wordSelectionEnable = true で、選択範囲のない状態でこのマクロを実行したときのみ「拡張自動選択」します (マルチカーソルに対応)。
※ 登録リストの単語に合致することはないとおもうので、範囲選択操作の補助機能としてご利用ください。




マクロを実行しても正しくトグル変換しないときやエラーになったときは、ダブルクォート"、カンマ,、角カッコ [ ] の過不足を確認してください( [ 角カッコ ] を閉じたうしろにはカンマ「 , 」が必要)。
また、おなじ単語を別のグループにも重複して登録していないかを確認してください(先に登録されたグループが優先的に参照されます)。


ソースコード

#title = "Yes/No マクロ"
#tooltip = "True と False を切り替える"
// #icon = "TF.ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",265

/**
 * --------------------------------------------------------
 * 「Yes/No マクロ」(True と False を切り替える)
 * sumemaru, 2018/11/20 - 2020/07/01
 * https://www.haijin-boys.com/wiki/TrueとFalse_を切り替える
 * --------------------------------------------------------
 * 選択範囲の文字列が "True" なら "False" に、"False" なら "True" にする
 * 
 * ■ マルチカーソル/複数選択範囲に対応 (2020/07/01)
 * ※ 矩形選択範囲から実行したときは、行に分けてからマルチ処理
 * 
 * ■ 選択範囲の文字列が日付なら「今日の日付」に変換(2020/07/01 追加)
 * ■ 同一記号の繰り返し文字列の自動選択 (2020/05/12 追加)
 * ※ e.g. #### や ※※※※ など、ダブルクリックでは範囲選択できないものを自動選択する
 *    ref. https://www.haijin-boys.com/wiki/拡張自動選択
 *    https://www.haijin-boys.com/wiki/%E6%8B%A1%E5%BC%B5%E8%87%AA%E5%8B%95%E9%81%B8%E6%8A%9E
 * 
 * ※ 単語グループの登録リストの仕様や変換処理の基本動作は 2018/11/27 版と共通
 * ※ Yes/No マクロでは、"任意の文字列" を "" に変換(文字列を削除)することはできない
 * ※ 単語グループ登録リストを上から順番に検索するので
 *    優先度の高いグループを上に置くこと
 */

// ---------- ▼ 設定項目 ▼ ----------

// ■ 選択範囲がないときにキャレット位置の単語を自動選択するか?
var wordSelectionEnable = true;
	// false なら、選択範囲のないときは変換しない

// ■ 「空白文字列の自動選択」に「全角空白」を含める
var fullWSpc = true;	// 		 
	// true 含める  (タブと全角/半角空白)/ false 含めない (タブと半角空白のみ)

// ■ 選択範囲の文字列が日付なら「今日の日付」に変換して終了する
var dateConvEnable = true;
	// true なら「今日の日付」に変換して終了(選択範囲を残さない)

// ■ 変換後に選択範囲を残すか?
var leftSelectionEnable = true;
	// true なら、連続実行でトグル変換できる

// ---------- ▲ 設定項目 ▲ ----------

var a = new Array(	// ←消しちゃダメ

// ---------- ▼ 単語グループを登録 ▼ ----------

  // 単語を "ダブルクォート" か 'シングルクォート' で囲い、カンマ「 , 」で区切って並べる。
  // ・グループを [ 角カッコ ] で囲い、うしろにもカンマ「 , 」を付けること。
  // ※マクロを実行して正しくトグルしないときやエラーになったときは、
  //  "ダブルクォート"/カンマ「 , 」/[ 角カッコ ] の過不足を確認。


  /* Positive or Negative */
  [ "True", "False" ], 
  [ "Yes", "No" ], 
  [ "On", "Off" ], 
  [ "Enable", "Disable" ], 
  [ "Positive", "Negative" ], 
  [ "Possible", "Impossible" ], 



  /* (中略) */



  [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ], 
  [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ], 
  [ "①", "②", "③", "④", "⑤", "⑥", "⑦", "⑧", "⑨", "⑩", "⑪", "⑫", "⑬", "⑭", "⑮", "⑯", "⑰", "⑱", "⑲", "⑳" ], 
  [ "➀", "➁", "➂", "➃", "➄", "➅", "➆", "➇", "➈", "➉" ], 


// ---------- ▲ 単語グループを登録 ▲ ----------

// var a = new Array ...	を閉じる
[] );		// ← 消しちゃダメ

// ---------- ▼ マルチカーソル/複数選択対応 ▼ ---------- //

var d = editor.ActiveDocument,  s = d.selection;
var sx = ScrollX,  sy = ScrollY;

/* マルチカーソル/複数選択範囲に対応 */
var dt = d.Text;
var sMode = s.Mode || 1;
var arg = [ wordSelectionEnable, fullWSpc, dateConvEnable, leftSelectionEnable, a ];

// 選択範囲が1つで矩形選択ではないとき
if ( sMode == 1 ) {
  YesNoMacro_Main( arg );
}
// 矩形選択または複数選択のとき
else {
  BeginUndoGroup();
  if ( ! d.ReadOnly ) { AddUndo(); }
  MultiFunction( YesNoMacro_Main, arg );
  EndUndoGroup();
}

/* 無駄な UNDO 履歴が残らないよう対策 */
// テキストの変更なしなら一度 UNDO して、拡張自動選択だけ再試行する
if ( sMode > 1 && d.Text === dt ) {
  if ( ! d.ReadOnly ) { d.Undo(); }
  if ( wordSelectionEnable ) {
    MultiFunction( SelectWordEx, fullWSpc );
  }
}

ScrollX = sx;  ScrollY = sy;

// ---------- ▲ マルチカーソル/複数選択対応 ▲ ---------- //

// ---------- ▼ メインコード ▼ ----------

/**
 * 関数 YesNoMacro_Main()
 * 「Yes/No マクロ」メインコード
 */
function YesNoMacro_Main( arg ) {
  var wordSelectionEnable = arg[0];
  var fullWSpc            = arg[1];
  var dateConvEnable      = arg[2];
  var leftSelectionEnable = arg[3];
  var a                   = arg[4];

  var d = editor.ActiveDocument,  s = d.selection;
  var st = yesNo = s.Text;

  // 選択範囲の文字列が日付なら「今日の日付」に変換して終了
  // ※ 選択範囲を残さない
  if ( ! d.ReadOnly && st && dateConvEnable ) {
    yesNo = DateOfToday( st );
    if ( yesNo !== st ) {
      s.Text = yesNo;
      return;
    }
  }

  // 単語の自動選択 または拡張自動選択
  // ※「同一記号の繰り返し」/「全角空白を含む空白文字列」/「日付」の
  //    拡張自動選択をしたときは終了
  if ( s.IsEmpty && wordSelectionEnable
  && SelectWordEx( fullWSpc ) ) {
    return;
  }
  st = yesNo = s.Text;

  if ( d.ReadOnly ) {
    Status = " ドキュメントは書き換え禁止です。";
    return;
  }
  else if ( ! st ) {
    Status = " 選択範囲がありません。";
    return;
  }
  else {
    // 「Yes/No」変換
    yesNo = ConvertYesNo( st, a );
    if ( yesNo && yesNo !== st ) {
      s.Text = yesNo;	// 変換完了

      // 単語先頭まで範囲選択
      if ( leftSelectionEnable ) {
        s.SetAnchorPos( s.GetActivePos() - yesNo.length );
      }
      // 単語先頭にカーソルを移動
      else if ( wordSelectionEnable ) {
        s.SetActivePos( s.GetActivePos() - yesNo.length );
      }
    }
  }
}

/**
 * 関数 ConvertYesNo( str, listArray )
 * Yes/No 変換
 * listArray の単語グループリストに str がマッチしたとき、変換した単語で返す
 * 2020/05/12: 変数を適宜追加、変数名を変更、コードを圧縮
 */
function ConvertYesNo( str, list ) {
  var word = "";

  ListLoop:
  for ( var i = 0, aLen = list.length, group, gLen;
  i < aLen; i ++ ) {
    group = list[i];  gLen = group.length;
    // 空のグループはスキップ
    if ( gLen < 2 ) { continue ListLoop; }

    GroupLoop:
    for ( var j = 0; j < gLen; j ++ ) {
      // 空の要素 "" と 0 フラグはスキップ
      if ( ! group[j] ) { continue GroupLoop; }

      // ヒット(完全一致)したら Hoge, hoge, HOGE
      if ( group[j] === str ) {
        word = ( j < gLen - 1 )   ? group[ j + 1 ] 	// ひとつ右の単語を返す
             : ( group[0] !== 0 ) ? group[0]		// いちばん左の単語を返す
             :/*(group[0] === 0)*/  group[1];		// ふたつめの単語を返す
        if ( word ) { break ListLoop; }
      }

      // 小文字にしてくらべてヒットしたら( 0 フラグなし)
      else if ( group[0] !== 0
      && group[j].toLowerCase() == str.toLowerCase() ) {
        word = ( j < gLen - 1 ) ? group[ j + 1 ]	// ひとつ右の単語
                                : group[0];			// いちばん左の単語
        // もとの単語が小文字のみなら小文字で、大文字のみなら大文字で返す
        word = ( str == str.toLowerCase() ) ? word.toLowerCase()
             : ( str == str.toUpperCase() ) ? word.toUpperCase()
                        /* else */          : "";	// 変換なし
        if ( word ) { break ListLoop; }
      }
    }
  }
  return word;
}

// ---------- ▲ メインコード ▲ ----------

// ---------- ▼ 拡張コード ▼ ----------

/**
 * 関数 SelectWordEx( optionfullWSpc )
 * 単語の自動選択 または
 * 「全角空白を含む空白文字列」/「同一記号の繰り返し」/「日付」の自動選択
 */
function SelectWordEx( fullWSpc ) {
  var d = editor.ActiveDocument,  s = d.selection;
  if ( s.IsEmpty ) { s.SelectWord(); }	// キャレットは選択範囲の末尾
  var st = s.Text;  if ( ! st ) { return false; }
  var ax = s.GetActivePointX( mePosLogical );
  var ay = s.GetActivePointY( mePosLogical );
  var line = d.GetLine( ay, 0 );
  var str1 = line.slice( 0, ax - 1 );	// キャレットより前の文字列
  var str2 = line.slice( ax - 1 );		// キャレットより後ろの文字列

  // ※ 全角空白をふくむ空白文字列全体を自動選択
  if ( fullWSpc && /^[\t  ]+$/.test( st ) ) {
    var sig1 = String( str1.match( /[\t  ]+$/ ) || "" );
    var sig2 = String( str2.match( /^[\t  ]+/ ) || "" );
    if ( sig1 || sig2 ) {
      s.SetAnchorPoint( mePosLogical, ax - sig1.length, ay );
      s.SetActivePoint( mePosLogical, ax + sig2.length, ay, true );
    }
    if ( s.Text !== st ) { return true; }
  }

  // ※ 同一記号の繰り返し文字列の自動選択
  if ( st.length === 1 ) {
    var sig1 = String( str1.match( new RegExp( "\\" + st + "+$", "" ) ) || "" );
    var sig2 = String( str2.match( new RegExp( "^\\" + st + "+", "" ) ) || "" );
    if ( sig1 || sig2 ) {
      s.SetAnchorPoint( mePosLogical, ax - sig1.length, ay );
      s.SetActivePoint( mePosLogical, ax + sig2.length, ay, true );
    }
    if ( s.Text !== st ) { return true; }
  }

  // ※ 日付の自動選択
  if ( /^\d{4}$/.test( st )	// yyyy
  && ( mmdd = str2.match( /^年(?:0?[1-9]|1[0-2])月(?:0?[1-9]|[12][0-9]|3[01])日/ ) )
  || ( mmdd = str2.match( /^([-.\/])(?:0?[1-9]|1[0-2])\1(?:0?[1-9]|[12][0-9]|3[01])\b/ ) )
  ) {
    s.SetActivePoint( mePosLogical, ax + String( mmdd[0] ).length, ay, true );
    return true;
  }
  var reg1 = /^(?:19|20)\d{2}([-.\/])(?:0?[1-9]|1[0-2])\1(?:0?[1-9]|[12][0-9]|3[01])$/;
  var reg2 = /^(?:19|20)\d{2}年(?:0?[1-9]|1[0-2])月(?:0?[1-9]|[12][0-9]|3[01])日$/;
  if ( /^(?:0?[1-9]|1[0-2])$/.test( st )	// mm
  && ( yy = str1.slice( 0, - st.length ).match( /\b\d{4}[-.\/年]$/ ) )
  && ( dd = str2.match( /^[-.\/月](?:0?[1-9]|[12][0-9]|3[01])日?(?=$|\D)/ ) )
  && ( reg1.test( yy + st + dd ) || reg2.test( yy + st + dd ) ) ) {
    s.SetAnchorPoint( mePosLogical, ax - ( yy + st ).length, ay );
    s.SetActivePoint( mePosLogical, ax + String( dd ).length, ay, true );
    return true;
  }
  if ( /^(?:0?[1-9]|[12][0-9]|3[01])$/.test( st )	// dd
  && ( yymm = str1.slice( 0, - st.length ).match( /\b\d{4}[-.\/年](?:0?[1-9]|1[0-2])[-.\/月]$/ ) )
  && ( dd = str2.match( /^日?(?=$|\D)/ ) )
  && ( reg1.test( yymm + st + dd ) || reg2.test( yymm + st + dd ) )
  ) {
    s.SetAnchorPoint( mePosLogical, ax - ( yymm + st ).length, ay );
    s.SetActivePoint( mePosLogical, ax + String( dd ).length, ay, true );
    return true;
  }
  return false;
}

/**
 * 関数 DateOfToday( str )
 * 選択範囲の文字列が日付なら今日の日付に変換する
 * ※ 月 日 はゼロパディングする
 */
function DateOfToday( str ) {
  var reg1 = /^(?:19|20)\d{2}([-.\/])(?:0?[1-9]|1[0-2])(\1)(?:0?[1-9]|[12][0-9]|3[01])(\b)$/;
  var reg2 = /^(?:19|20)\d{2}(年)(?:0?[1-9]|1[0-2])(月)(?:0?[1-9]|[12][0-9]|3[01])(日)$/;
  if ( str.match( reg1 ) || str.match( reg2 ) ) {
    var sep1 = RegExp["$1"], sep2 = RegExp["$2"], sep3 = RegExp["$3"];
    var Pad  = function( tmp ) { return tmp < 10 ? "0" + tmp : tmp; }
    var dt   = new Date();
    var yyyy = dt.getFullYear() + sep1;
    var mm   = Pad( dt.getMonth() + 1 ) + sep2;
    var dd   = Pad( dt.getDate() ) + sep3;
    str = yyyy + mm + dd;
  }
  return str;
}

/**
 * 関数 MultiFunction( Fn, arg1 )
 * マルチカーソル(複数選択範囲)に対応させる
 * 第1引数: Function; 選択範囲ごとに適用する処理の関数
 * 第2引数以降: Function に渡す引数をまとめた配列
 */
function MultiFunction( Fn, arg ) {
  var d = editor.ActiveDocument;
  var s = d.selection;

  // 矩形選択範囲は行に分ける
  s.Mode = meModeMulti;

  // 選択範囲の座標を取得
  var sCount = s.Count;
  var Sel = [];
  for ( var i = 0; i < sCount; i ++ ) {
    Sel[i] = {
      act: s.GetActivePos( i ),
      anc: s.GetAnchorPos( i )
    };
  }

  // 各選択範囲を処理
  var r = selEx = false;
  for ( var i = 0, diff = 0, dl; i < sCount; i ++ ) {
    dl = d.TextLength;
    s.SetActivePos( Sel[i].act + diff );
    s.SetAnchorPos( Sel[i].anc + diff );

    Fn( arg );	// YesNoMacro_Main() 関数で Yes/No 変換

    // Fn() の残した選択範囲(またはキャレット位置)を回収
    Sel[i].act = s.GetActivePos();
    Sel[i].anc = s.GetAnchorPos();
    diff += d.TextLength - dl;	// 文字数の増減量(累積)
  }

  // マルチカーソル(複数選択範囲)を復帰
  for ( var i = 0; i < sCount; i ++ ) {
    s.AddPos( Sel[i].anc, Sel[i].act );
  }
}

// ---------- ▲ 拡張コード ▲ ----------

メモ

2018/11/23?:
初版
2018/11/25:
ソースコードを変更しました(3つ以上のループ変換に対応)。
2018/11/27:
ソースコードを変更しました(完全一致フラグ0, と、ループ禁止フラグ, "" を追加)。
2019/05/06:
「ToDoリストモード」搭載の改造版のリンクを追加しました(単語登録リストの仕様は 2018/11/27 の通常版とおなじ)。
2020/05/12:
ソースコードを更新しました(単語登録リストの仕様は 2018/11/27 の通常版とおなじまま)。
ZIP 書庫内のソースコードでは、単語グループのリストは sukemaru の自家用状態のまま 300 件(グループ)ぐらい詰めこんであります。
2020/07/01:
  • 「マルチカーソル/複数選択範囲」に対応するよう、ソースコードを更新しました(単語登録リストの仕様は 2018/11/27 の通常版とおなじまま)。
  • 自家用だった「拡張自動選択」機能の一部を追加しました。
  • 「ToDoリストモード」搭載の改造版は 2020/05/12 から変更していません(マルチカーソル 非対応)。
スポンサーリンク