「
マルチカーソル選択範囲の並べ替え
」を編集中 (節単位)
ナビゲーションに移動
検索に移動
警告:
ログインしていません。編集を行うと、あなたの IP アドレスが公開されます。
ログイン
または
アカウントを作成
すれば、あなたの編集はその利用者名とともに表示されるほか、さまざまなメリットもあります。
スパム攻撃防止用のチェックです。 決して、ここには、値の入力は
しない
でください!
== ソースコード == <syntaxhighlight lang="javascript" style="height:100em; overflow:auto;"> #title = "選択範囲の並べ替え" #tooltip = "マルチカーソル選択範囲の並べ替え または 入れ替え" #icon = "arrows_swap_horaizontal[7].ico" // #title = "選択範囲の並べ替え(昇順/降順)" // #title = "選択範囲の並べ替え(反転)" // #title = "選択範囲の並べ替え(後ろ送り)" // #title = "選択範囲の並べ替え(逆送り)" /** * --------------------------------------------------------- * 「選択範囲の並べ替え」マクロ * sukemaru, 2020/06/29 - 2020/07/06 * --------------------------------------------------------- * ・マルチカーソル選択範囲を「昇順/降順」または「逆順 (反転)」で並べ替え * または選択範囲の並び順を「ひとつずらす (後ろ送り/逆送り)」 * ・選択範囲が2つなら「入れ替え」 * ・連続実行でトグル変換 * * 2020/07/04: 「逆順で並べ替え (並び順を反転)」モードを追加 * 「各選択範囲の末尾調整」を追加 * 2020/07/06: 「後ろ送り(右・下にひとつずらす)」モードと * 「逆送り(左・上にひとつずらす)」モードを追加 * GetKeyState.exe による4モード切り替え処理を追加 * * 【仕様上の制限】 * ・動作要件:Mery Ver 3.0.1 以降 * ・元々の並び順が昇順または降順でなかった場合 * 連続実行で「昇順/降順トグル」しても元の並び順にはなりません。 * ⇒ 元々の並び順に戻す場合は「元に戻す (Ctrl+Z)」を連打 * ・矩形選択範囲は行に分けてから並べ替えます。 ⇒ 実行後は複数選択状態 * (※ 元の矩形選択のかたちが歪だった場合に、矩形で復帰できないため) * ・選択範囲復帰後の各キャレット位置は、各選択範囲の先頭になります。 * (※ 行単位で並べ替えたときに、キャレットが末尾だと分かりづらいため) * ・ブックマークを考慮しません。 * ・並べ替え処理中に選択範囲(ゼロ幅も含めて)の数が変わってしまったり * 文書全体の文字数が変わってしまう場合は、並べ替えの処理ををキャンセルします。 * (※ 選択範囲が結合されてしまう場合もキャンセル * ※ 失敗した試行の結果は「やり直し (Ctrl+Y)」×2回すると確認できます) */ // ---------- ▼ 設定項目 ▼ ---------- // // ■ 「昇順/降順」で、半角数字を数値で評価して並べ替える // (各選択範囲内の最初の半角数字部分を数値として扱う ...たぶん小数も可) var sortByNum = false; /** * true: 数値順 * 1 < 002 < 3 < 10 < 020 * -2.5 < -2 < -1 < 0 < 1 < 1.2 < 1.2.30 < 1.2.4 * * false: 文字順 @ unicode * 002 < 020 < 1 < 10 < 3 * -1 < -2 < -2.5 < 0 < 1 < 1.2 < 1.2.30 < 1.2.4 * * ※ true の場合でも「1.2.30」や「1.2.4」などは * 「1.2」までを数値(小数)として評価し * それ以降の「.30」や「.4」は文字列として評価するので * ビルド番号や IP アドレスなどは数値順にならない * また「ほげ 1 ふが 2 ぴよ 3」のように2ヵ所以上数字が出現する場合 * 2つめ以降の数字はすべて文字列として評価する */ // ■ 各選択範囲の末尾調整をする var chompEnable = false; /** * true: 各選択範囲の末尾が改行のとき、末尾改行を選択範囲から除外する * false: 選択範囲の末尾調整をしない * * ※ true の場合、並べ替え後も末尾改行は除外したまま */ // ■ 「並べ替え」の動作モード var multiSelMode = 0; /** 凡例: 元の文字列 1回目 2回目 3回目 * 0: 昇順/降順 で並べ替え 1, 2, 3, 0 ⇒ 0, 1, 2, 3 ⇒ 3, 2, 1, 0 ⇒ 0, 1, 2, 3 * 1: 逆順で並べ替え (反転) 1, 2, 3, 0 ⇒ 0, 3, 2, 1 ⇒ 1, 2, 3, 0 ⇒ 0, 3, 2, 1 * 2: 後ろ送り(右・下にずらす) 1, 2, 3, 0 ⇒ 0, 1, 2, 3 ⇒ 3, 0, 1, 2 ⇒ 2, 3, 0, 1 * 3: 逆送り (左・上にずらす) 1, 2, 3, 0 ⇒ 2, 3, 0, 1 ⇒ 3, 0, 1, 2 ⇒ 0, 1, 2, 3 * * ※ 凡例は、各数字1文字ずつ複数選択(4ヶ所)したときの動作パターン */ // ■ 選択範囲が3つ以上のとき Ctrl/Shift キーで動作モードを切り替える var gksEnable = 0; /** * 0: 動作モードの切り替えをしない(GetKeyState.exe を使用しない) * 1: Ctrl キーで「昇順/降順」⇔「逆順」または「後ろ送り」⇔「逆送り」 * 2: Shift キーで「昇順/降順」⇔「後ろ送り」または「逆順」⇔「逆送り」 * 3: Ctrl+Shift キーで「昇順/降順」⇔「逆送り」または「逆順」⇔「後ろ送り」 * * ※ 3 の場合、GetKeyState.exe を2回起動する * ※ 1 ~ 3 でも、選択範囲が2つなら GetKeyState.exe を起動しない(選択範囲の入れ替え) * * ※ 要:「GetKeyState.exe(キー状態取得実行ファイル)」 * https://www.haijin-boys.com/wiki/GetKeyState.exe(%E3%82%AD%E3%83%BC%E7%8A%B6%E6%85%8B%E5%8F%96%E5%BE%97%E5%AE%9F%E8%A1%8C%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB) */ // ■ GetKeyState.exe のフルパスを指定する場合 var gksPath = ""; /** * 未指定 "" なら、Mery インストールフォルダの Macros\GetKeyState.exe * ※ GetKeyState.exe なしのときも "" にすること。 * ※ パス指定での区切り文字の \ 記号はふたつがさね「\\」で記述すること。 */ // ---------- ▲ 設定項目 ▲ ---------- // // 実行 SortByBlock( sortByNum, multiSelMode, chompEnable, gksEnable, gksPath ); /** * 関数 SortByBlock() * マルチカーソル複数選択範囲の入れ替え * ・ マルチカーソル選択範囲を「昇順/降順」で並べ替え、または「反転 (逆転)」 * * 2020/07/06: 第ニ引数を reverseMode (true/false)から multiSelMode (0~3) に変更し * 動作モード「後ろ送り (右・下方向にずらす )」「逆送り (左・上方向にずらす )」を追加 * GetKeyState.exe による4モード切り替えを追加 */ function SortByBlock( sortByNum, multiSelMode, chompEnable, gksEnable, gksPath ) { var d = editor.ActiveDocument; var s = d.selection; var ty = s.GetTopPointY( mePosLogical ); var by = s.GetBottomPointY( mePosLogical ); var sMode = s.Mode || 1; if ( d.ReadOnly ) { Status = " このドキュメントは書き換え禁止です。"; return; } if ( s.IsEmpty || sMode == meModeStream || ( sMode == meModeBox && ty === by ) ) { Status = " 並べ替えられる選択範囲がありません。"; return; } var sx = ScrollX, sy = ScrollY; BeginUndoGroup(); AddUndo(); // /* 「昇順/降順」マクロ専用: 「すべての選択範囲を行に分割して並べ替え」 */ // // 末尾改行の調整 // if ( chompe0 ) { // MultiFunction( PseudoChomp ); // editor.ExecuteCommandByID( 2254 ); // 「選択範囲を行に分ける」 // } // 矩形選択を「行に分ける」(論理行) s.Mode = meModeMulti; // 末尾改行の調整 if ( sMode == meModeMulti && chompEnable ) { MultiFunction( PseudoChomp ); } // 各選択範囲の先頭/末尾の座標と文字列を取得 var dt = d.Text; var sCount = s.Count; var Sel = [], Str = []; var act, anc, tp, bp; for ( var i = 0; i < sCount; i ++ ) { act = s.GetActivePos( i ); anc = s.GetAnchorPos( i ); tp = Math.min( act, anc ); bp = Math.max( act, anc ); Sel[i] = { tp: tp, bp: bp }; Str[i] = dt.slice( tp, bp ); } var tmp = Str.toString(); /* 「選択範囲の並べ替え」マクロ用 */ // 選択範囲が3つ以上のとき、GetKeyState.exe で動作モードを切り替え GetKeyState: if ( gksEnable && sCount > 2 ) { var gks = gksPath || editor.FullName.replace( /[^\\]+$/, "Macros\\GetKeyState.exe" ); gksEnable = new ActiveXObject( "Scripting.FileSystemObject" ).FileExists( gks ) ? gksEnable : 0; if ( ! gksEnable ) { break GetKeyState; } var WshShell = new ActiveXObject( "WScript.Shell" ); // ● Ctrl キーあり if ( gksEnable % 2 && WshShell.Run( '"' + gks + '" Ctrl', 0, true ) === 1 ) { // 「昇順/降順」⇔「逆順」 または 「後ろ送り」⇔「逆送り」 if ( multiSelMode % 2 ) { multiSelMode --; } else { multiSelMode ++; } } // ● Shift キーあり if ( gksEnable > 1 && WshShell.Run( '"' + gks + '" Shift', 0, true ) === 1 ) { // 「昇順/降順」⇔「後ろ送り」 または 「逆順」⇔「逆送り」 if ( multiSelMode > 1 ) { multiSelMode -= 2; } else { multiSelMode += 2; } } } // 逆順で並べ替え(反転) if ( sCount === 2 || multiSelMode == 1 ) { $status = " 逆順で並べ替え (反転)"; Str.reverse(); } else if ( multiSelMode == 0 ) { // 昇順で並べ替え $status = " 昇順で並べ替え"; Str.sort( Sort ); // すでに昇順だった場合は降順で並べ替え(反転) if ( Str.toString() === tmp ) { $status = " 降順で並べ替え"; Str.reverse(); } } else if ( multiSelMode === 2 ) { // 後ろ送り(右・下方向にひとつずらす) $status = " 後ろ送り (右・下にひとつずらす)"; Str.unshift( Str.pop() ); } else if ( multiSelMode === 3 ) { // 逆送り(左・上方向にひとつずらす) $status = " 逆送り (左・上にひとつずらす)"; Str.push( Str.shift() ); } // 変更なしなら UNDO 履歴を残さない if ( Str.toString() === tmp ) { EndUndoGroup(); d.Undo(); Status = " 並べ替えなし"; return; } // 各選択範囲を処理 for ( var i = 0, diff = 0, dl = d.TextLength; i < sCount; i ++ ) { // dl = d.TextLength; s.SetActivePos( Sel[i].bp + diff ); s.SetAnchorPos( Sel[i].tp + diff ); // 並べ替えを適用 s.Text = Str[i]; // 復帰用選択範囲の先頭/末尾 Sel[i].bp = s.GetActivePos(); Sel[i].tp = Sel[i].bp - Str[i].length; // 文字数の増減量(累積) // diff += d.TextLength - dl; diff += ( - dl ) + ( dl = d.TextLength ); } // マルチカーソル/複数選択範囲を復帰 s.SetActivePos( Sel[ sCount - 1 ].tp, true ); for ( var i = 0; i < sCount; i ++ ) { // キャレットは各選択範囲の先頭 s.AddPos( Sel[i].bp, Sel[i].tp ); } EndUndoGroup(); // 選択範囲の数が変わってしまう場合(マージ)や // 文書全体の文字数が変わってしまう場合は失敗 if ( sMode == meModeMulti && s.Count !== sCount || diff ) { AddUndo(); d.Undo(); d.Undo(); Status = " 並べ替え失敗"; } else { Status = ( sCount === 2 ) ? " 選択範囲を入れ替え" : $status; } ScrollX = sx; ScrollY = sy; } /** * 関数 Sort( a, b ) * 昇順で並べ替え * 半角数字部分は「数値」または「文字列」で評価 * ※ sortByNum はグローバルスコープの設定変数 */ function Sort( a, b ) { var reg = /^(.*?)(-?\d+(?:\.\d+)?)/; var aa = reg.exec( a ), a1 = aa ? aa[1] : ""; var bb = reg.exec( b ), b1 = bb ? bb[1] : ""; var a2 = a, b2 = b; if ( sortByNum && aa && bb && a1 === b1 ) { a2 = Number( aa[2] ); b2 = Number( bb[2] ); } return ( a2 !== a && a2 !== b2 ) ? a2 - b2 : ( a < b ) ? -1 : ( a > b ) ? 1 :/* else */ 0; } /** * 関数 PseudoChomp() * 選択範囲から末尾改行を除去する * ※ 選択範囲の先頭位置は変更しない */ function PseudoChomp() { var d = editor.ActiveDocument; var s = d.selection; if ( s.Text.slice( -1 ) === "\n" ) { var ty = s.GetTopPointY( mePosLogical ); var tx = s.GetTopPointX( mePosLogical ); var by = s.GetBottomPointY( mePosLogical ); by --; s.SetActivePoint( mePosLogical, tx, ty ); s.SetAnchorPoint( mePosLogical, d.GetLine( by, 0 ).length + 1, by ); } } /** * 関数 MultiFunction( Fn, arg ) * マルチカーソル(複数選択範囲)に対応させる * マルチカーソル(複数選択範囲)に対応させる * 第1引数: Function; 選択範囲ごとに適用する処理の関数 * 第2引数: Function に渡す引数をまとめた配列 * * ※ 並べ替えマクロ用カスタマイズ: * ⇒ PseudoChomp() 関数にしか使わないので、文字数の増減量をチェックしない */ 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 ) }; } // 各選択範囲を処理 for ( var i = 0, diff = 0, dl; i < sCount; i ++ ) { // dl = d.TextLength; s.SetAnchorPos( Sel[i].anc + diff ); s.SetActivePos( Sel[i].act, true + diff ); Fn( arg ); // PseudoChomp() 関数 // 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 ); } } </syntaxhighlight>
編集内容の要約:
MeryWikiへの投稿はすべて、他の投稿者によって編集、変更、除去される場合があります。 自分が書いたものが他の人に容赦なく編集されるのを望まない場合は、ここに投稿しないでください。
また、投稿するのは、自分で書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください(詳細は
MeryWiki:著作権
を参照)。
著作権保護されている作品は、許諾なしに投稿しないでください!
このページを編集するには、下記の数式を計算してその答えを欄に入力してください (
ヘルプ
):
いちたすには =
キャンセル
編集ヘルプ
(新しいウィンドウで開きます)
スポンサーリンク
ナビゲーション メニュー
個人用ツール
ログインしていません
トーク
投稿記録
アカウント作成
ログイン
名前空間
ページ
議論
日本語
表示
閲覧
編集
履歴表示
その他
検索
スポンサーリンク
スポンサーリンク
案内
メインページ
ヘルプ
よくある質問
マクロリファレンス
マクロライブラリ
プラグインライブラリ
構文ファイル
テーマ
寄付・開発支援
練習用ページ
開発室
開発者のブログ
ツール
スポンサーリンク