「
マルチカーソル用:「昇順/降順」または「逆順」で並べ替え
」を編集中 (節単位)
ナビゲーションに移動
検索に移動
警告:
ログインしていません。編集を行うと、あなたの IP アドレスが公開されます。
ログイン
または
アカウントを作成
すれば、あなたの編集はその利用者名とともに表示されるほか、さまざまなメリットもあります。
スパム攻撃防止用のチェックです。 決して、ここには、値の入力は
しない
でください!
== ソースコード == <syntaxhighlight lang="javascript" style="height:100em; oVerflow:auto;"> #title = "昇順/降順 トグル" #tooltip = "昇順で並べ替え/降順で並べ替え" #icon = "sort_by_alpha_a_to_z.ico" // #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",145 // #title = "逆順で並べ替え トグル" // #tooltip = "逆順で並べ替え" // #icon = "arrows_swap_Vertical[7].ico" /** * -------------------------------------------------------- * 「昇順/降順 または 逆順 で並べ替え」 * マルチカーソル対応版 * sukemaru, 2020/07/04 - 2020/07/08 * -------------------------------------------------------- * 論理行単位で「昇順/降順」または「逆順」で並べ替え * * ※ reVerseMode = true で「逆順で並べ替え (並び順を反転)」 * * 複数選択範囲から実行した場合は、 * ・それぞれの選択範囲内を並べ替え (multiSelMode = 0) * ・すべての選択範囲を行に分割して一括で並べ替え (multiSelMode = 1) * ※ いずれの場合も、選択範囲が2つでいずれも改行を含んでいないなら「入れ替え」 * * 【仕様上の制限】 * ・動作要件:Mery Ver 3.0.1 以降 * ・基本的に、選択範囲末尾が改行記号(末尾位置が論理行の行頭)のときは * 末尾改行より前の部分だけを並べ替えします。 * ・元々の並び順が昇順または降順でなかった場合 * 連続実行で「昇順/降順トグル」しても元の並び順にはなりません。 * ⇒ 元々の並び順に戻す場合は「元に戻す (Ctrl+Z)」を連打 * ・矩形選択範囲は行に分けてから並べ替えます。 ⇒ 実行後は複数選択状態 * (※ 元の矩形選択のかたちが歪だった場合に、矩形で復帰できないため) * ・複数行選択状態から実行した場合、並べ替え後(選択範囲復帰後)の * 各キャレット位置は各選択範囲の先頭になります。 * (※ 行単位で並べ替えたときに、キャレットが末尾だと分かりづらいため) * ・ブックマークを考慮しません。 * ・並べ替え処理中に選択範囲(ゼロ幅も含めて)の数が変わってしまったり * 文書全体の文字数が変わってしまう場合は、並べ替えの処理ををキャンセルします。 * (※ 選択範囲が結合されてしまう場合もキャンセル * ※ 失敗した試行の結果は「やり直し (Ctrl+Y)」×2回すると確認できます) */ /* ---------- ▼ 設定項目 ▼ ---------- */ // ■ 複数選択範囲での動作モード var multiSelMode = 0; /** * multiSelMode = 0: 各選択範囲ごとに「行並べ替え」 * multiSelMode = 1: すべての選択範囲を行に分割して「行並べ替え」 * * ※ 0 のばあい、それぞれの選択範囲ごとに * 各選択範囲内を「昇順/降順」で並べ替える(選択範囲が1行内なら並べ替えなし) * すべての選択範囲にたいして選択的・統一的に「昇順」または「降順」を * 適用することはできない * ※ 1 のばあい、各選択範囲から末尾改行を除去してから行に分割して * すべての選択範囲を「昇順/降順」または「逆順」で並べ替える * ※ いずれの場合も、各選択範囲の「論理行全体」への自動拡張はしない * ※ いずれの場合も、選択範囲が2つでいずれも改行を含んでいないなら「入れ替え」 */ // ■「昇順/降順」ではなく「逆順で並べ替え (並び順を反転)」する var reVerseMode = false; /** * true: 逆順で並べ替え (並び順を反転) * false: 昇順/降順 で並べ替え */ // ■ 半角数字を数値で評価して「昇順/降順」で並べ替える // (各選択範囲内の最初の半角数字部分を数値として扱う ...たぶん小数も可) 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つめ以降の数字はすべて文字列として評価する */ /* ------------------------------ */ // ● Ctrl キーで動作モードを切り替え(要:GetKeyState.exe) var gksEnable = 0; /** * 0 なら、動作モードの切り替えなし * 1 なら、multiSelMode を切り替え * 2 なら、reVerseMode を切り替え * 3 なら、sortByNum を切り替え */ // ■ GetKeyState.exe のフルパスを指定する場合 var gksPath = ""; /** * 未指定 "" なら、Mery インストールフォルダの Macros\GetKeyState.exe * ※ GetKeyState.exe なしのときも "" にすること。 * ※ パス指定での区切り文字の \ 記号はふたつがさね「\\」で記述すること。 */ /* ---------- ▲ 設定項目 ▲ ---------- */ ( function Main() { /* ▼ 前処理 ▼ */ var d = editor.ActiveDocument, 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 || ! /[^\n]/.test( s.Text ) ) { Status = " 選択範囲がありません。"; return; } else if ( ( sMode == 2 && ty === by ) || ( sMode == 1 && ty === by ) ) { Status = " 並べ替えられる選択範囲がありません。"; return; } /* GetKeyState.exe による修飾キー判定 */ var gks = gksPath || editor.FullName.replace( /[^\\]+$/, "Macros\\GetKeyState.exe" ); gksEnable = new ActiveXObject( "Scripting.FileSystemObject" ).FileExists( gks ) ? gksEnable : 0; // ● Ctrl キーで動作モードを切り替え if ( ( ( gksEnable === 1 && sMode == 3 ) || gksEnable === 2 || gksEnable === 3 ) && new ActiveXObject( "WScript.Shell" ).Run( '"' + gks + '" ctrl', 0, true ) === 1 ) { if ( gksEnable === 1 ) { multiSelMode = ! multiSelMode; } else if ( gksEnable === 2 ) { reVerseMode = ! reVerseMode; } else if ( gksEnable === 3 ) { sortByNum = ! sortByNum; } } /* ▼ 本処理 ▼ */ var start = new Date(); // 所要時間計測(開始) editor.ExecuteCommandByID( MEID_WINDOW_ACTIVE_PANE = 2189 ); // アクティブなペイン var sx = ScrollX, sy = ScrollY; /* マルチカーソル/複数選択に対応 */ var arg = [ sortByNum, reVerseMode ]; // ● 選択範囲が1つで矩形選択ではないとき if ( sMode == 1 ) { SortToggle_Main( arg ); } // ● 矩形選択 ⇒ 複数選択で返す else if ( sMode == 2 ) { SortByBlock( sortByNum, reVerseMode, false ); } // 選択範囲が2つでいずれも改行を含んでいないなら「入れ替え」 else if ( ! multiSelMode && s.Count === 2 && s.Count === ( s.Text.match( /\n/g ) || [] ).length && s.GetActivePos( 0 ) !== s.GetAnchorPos( 0 ) && s.GetActivePos( 1 ) !== s.GetAnchorPos( 1 ) ) { SortByBlock( sortByNum, true, false ); } // ● 複数選択 ×「すべての選択範囲を行に分割して並べ替え」のとき else if ( sMode == 3 && multiSelMode ) { SortByBlock( sortByNum, reVerseMode, false, true ); } // ● 複数選択 ×「各選択範囲ごとに行並べ替え」のとき else { var dt = d.Text; BeginUndoGroup(); AddUndo(); MultiFunction( SortToggle_Main, arg ); Status = ( reVerseMode ) ? Status : " 昇順/降順 で並べ替え"; Status += "(複数選択範囲)"; EndUndoGroup(); /* ▼ 後処理 ▼ */ if ( d.Text === dt ) { d.Undo(); Status = " 並べ替えなし"; } } ScrollX = sx; ScrollY = sy; var elapsedSec = ( ( new Date() - start ) / 1000 ).toFixed( 3 ); Status += " [ " + elapsedSec.replace( /\./, ". " ) + " 秒 ]"; } )(); // Main /** * 関数 SortToggle_Main( [ sortByNum, reVerseMode ] ) * 「昇順で並べ替え/降順で並べ替え」+「逆順で並べ替え」マクロ */ function SortToggle_Main( arg ) { var sortByNum = arg[0]; var reVerseMode = arg[1]; var d = editor.ActiveDocument, s = d.selection; var st = s.Text; var reg1 = /\n?$/, n = st.match( reg1 ); st = st.replace( reg1, "" ); if ( st.indexOf( "\n" ) === -1 ) { return; } st = st.split( "\n" ); var tmp = st.toString(); var $status = ""; // 逆順で並べ替え if ( reVerseMode ) { $status = " 逆順で並べ替え"; st.reVerse(); } else { // 昇順で並べ替え $status = " 昇順で並べ替え"; st.sort( Sort ); // すでに昇順だった場合は降順で並べ替え(反転) if ( st.toString() === tmp ) { $status = " 降順で並べ替え"; st.reVerse(); } } // 並べ替えを適用 if ( st.toString() !== tmp ) { var act = s.GetActivePos(); var anc = s.GetAnchorPos(); s.Text = st.join( "\n" ) + n; // 選択範囲を復帰 s.SetActivePos( anc ); s.SetActivePos( act, true ); Status = $status; } // 並べ替え なし else { Status = " 並べ替えなし"; } } /** * 関数 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 に渡す引数をまとめた配列 * * ※ 並べ替えマクロ用カスタマイズ: * ⇒ キャレットは各選択範囲の先頭 */ function MultiFunction( Fn, arg ) { var d = editor.ActiveDocument; var s = d.selection; // 矩形選択範囲は行に分ける s.Mode = 3; // 選択範囲の座標を取得 var sCount = s.Count; var Sel = []; for ( var i = 0; i < sCount; i ++ ) { act = s.GetActivePos( i ); anc = s.GetAnchorPos( i ); Sel[i] = { tp: Math.min( act, anc ), bp: Math.max( act, anc ) }; } // 各選択範囲を処理 for ( var i = 0, diff = 0, dl = d.TextLength; i < sCount; i ++ ) { // dl = d.TextLength; s.SetAnchorPos( Sel[i].bp + diff ); s.SetActivePos( Sel[i].tp + diff, true ); Fn( arg ); // SortToggle_Main() 関数で並べ替え // Fn() の残した選択範囲(またはキャレット位置)を回収 act = s.GetActivePos(); anc = s.GetAnchorPos(); Sel[i] = { tp: Math.min( act, anc ), bp: Math.max( act, anc ) }; // diff += d.TextLength - dl; // 文字数の増減量(累積) diff += ( - dl ) + ( dl = d.TextLength ); } // マルチカーソル(複数選択範囲)を復帰 s.SetAnchorPos( Sel[ sCount - 1 ].bp ); s.SetActivePos( Sel[ sCount - 1 ].tp, true ); for ( var i = 0; i < sCount; i ++ ) { // キャレットは各選択範囲の先頭 s.AddPos( Sel[i].bp, Sel[i].tp ); } } /** * 関数 SortByBlock() * マルチカーソル複数選択範囲の並べ替え * ※ マルチカーソル選択範囲を「昇順/降順」または「逆順」で並べ替え */ function SortByBlock( sortByNum, reVerseMode, chompEnable, chompe0 ) { var d = editor.ActiveDocument; var s = d.selection; var ty = s.GetTopPointY( mePosLogical ); var by = s.GetBottomPointY( mePosLogical ); var sMode = s.Mode || 1; BeginUndoGroup(); AddUndo(); /* 「昇順/降順」マクロ用: 「すべての選択範囲を行に分割して並べ替え」 */ // 末尾改行の調整 if ( chompe0 ) { MultiFunction( PseudoChomp ); editor.ExecuteCommandByID( 2254 ); // 「選択範囲を行に分ける」 } // 矩形選択を「行に分ける」(論理行) s.Mode = meModeMulti; // 各選択範囲の先頭/末尾の座標と文字列を取得 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(); // 逆順で並べ替え if ( sCount === 2 || reVerseMode ) { $status = " 逆順で並べ替え"; Str.reVerse(); } else { // 昇順で並べ替え $status = " 昇順で並べ替え"; Str.sort( Sort ); // すでに昇順だった場合は降順で並べ替え(反転) if ( Str.toString() === tmp ) { $status = " 降順で並べ替え"; Str.reVerse(); } } // 変更なしなら 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; } } </syntaxhighlight>
編集内容の要約:
MeryWikiへの投稿はすべて、他の投稿者によって編集、変更、除去される場合があります。 自分が書いたものが他の人に容赦なく編集されるのを望まない場合は、ここに投稿しないでください。
また、投稿するのは、自分で書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください(詳細は
MeryWiki:著作権
を参照)。
著作権保護されている作品は、許諾なしに投稿しないでください!
このページを編集するには、下記の数式を計算してその答えを欄に入力してください (
ヘルプ
):
いちたすには =
キャンセル
編集ヘルプ
(新しいウィンドウで開きます)
スポンサーリンク
ナビゲーション メニュー
個人用ツール
ログインしていません
トーク
投稿記録
アカウント作成
ログイン
名前空間
ページ
議論
日本語
表示
閲覧
編集
履歴表示
その他
検索
スポンサーリンク
スポンサーリンク
案内
メインページ
ヘルプ
よくある質問
マクロリファレンス
マクロライブラリ
プラグインライブラリ
構文ファイル
テーマ
寄付・開発支援
練習用ページ
開発室
開発者のブログ
ツール
スポンサーリンク