etsuxのブログ

自分がハマったことなどを記録しています。

サクラエディタのソート用マクロとVBScriptのArrayのArrayListへの格納方法

答えは、Alt+A=昇順、Alt+D=降順、Alt+M=連続重複削除、でした。

 

サクラエディタのマクロで、編集画面上でソートができると便利なので、ソート用マクロを作ってみようと思う。

秀丸エディタのときはVC++で実行ファイルを作ってソートを実現したが、サクラエディタVBScriptが使えるのでVBScript縛りで実現してみる。 +ソースコードの行数も50行程度までの縛りで。

基本的な処理は以下になる。

  1. 選択範囲を切り取り
  2. クリップボードの内容をソート
  3. 貼り付け

クリップボードの内容をソートする処理は以下になる。

  1. クリップボードを文字列で取得
  2. 文字列を改行で分割して配列化
  3. 配列をソート
  4. 改行で配列要素を結合し文字列化
  5. クリップボードに戻す

クリップボード周りはサクラエディタのマクロ関数にあるので問題なし。

文字列の分割と配列要素の結合はVBScriptの機能にあるので問題なし。

VBScriptのArrayにはソートがないが、ArrayListを使用するとソートもできるみたい。

実験記録 No.02 : VBSで動的配列(ArrayList)を使う

ただ、基本的にはVBScriptで書くとするとArrayを途中でArrayListに格納したくなるが、1件ずつ格納する以外に方法が見つからない。

ArrayListのメソッドではどれもダメだった。

  • AddRange … ICollectionのオブジェクトでないとダメ
  • Insert … 値を挿入するメソッドで、配列を挿入することはできない
  • コンストラクタ … CreateObjectでは渡せない、など

Arrayを使わない場合にはSystem.String→Split→System.Collections.ArrayListのようなことがあるが、System.StringはCreateOjectには使えないようなので、System.Text.StringBuilder→ToStringかな?

...結局は、Stringに代入する方法が見つからなかったので断念。

Arrayを1件ずつArrayListにAddする方法でやってみた。

あと、いろいろなソート方法を指定できるのもいいかなと思ったけど、以下の2点でこちらも断念。

  • VBScriptでソート指定用のダイアログを出してその結果を受け取る必要あり。
  • SortメソッドのコールバックにIComparerを用意する必要あり。

試行錯誤の結果、ソート用マクロはこうなった。

  • 2017/6/8 重複なしでソートできるようにした。

 

マクロファイル:C:\Users\ユーザ名\AppData\Roaming\sakura\clipsort.vbs

'ソート方法を指定(選択ダイアログを作れなかった)
rc = Editor.YesNoBox("昇順=はい、降順=いいえ を選択してください。")
Select Case rc
    Case 6 'はい
        order = 0 '昇順
    Case 7 'いいえ
        order = 1 '降順
End Select
rc = Editor.YesNoBox("重複あり=はい、重複なし=いいえ を選択してください。")
Select Case rc
    Case 6 'はい
        unique = 0 '重複あり
    Case 7 'いいえ
        unique = 1 '重複なし
End Select
'選択状態
mode = Editor.IsTextSelected()
Select Case mode
    Case 0 '選択なし=全体をソート
        Editor.SelectAll(0)
    Case 1 '選択
        mode = 0 '通常貼り付け
    Case 2 '矩形選択
        mode = 1 '矩形貼り付け
End Select
'選択部分をクリップボードにコピー
Editor.Cut(0)
'コピーした文字列を取得
clip = Editor.GetClipboard(0)
'改行(LF)で分割(CR/LFはCRを残す)
arr = Split(clip, vbLf)
'ソートが可能なArrayListオブジェクトを用意
Dim list
Set list = CreateObject("System.Collections.ArrayList")
'領域拡張が起こらないよう要素数を事前に設定
list.Capacity = UBound(arr)
'最後の空行を含めない行数を算出
n = UBound(arr)-1
If arr(n) = "" or arr(n) = vbCr Then
	n = n - 1
End If
'Array→ArrayListのコピー(他に方法がなかった)
For i=0 to n
    list.add(arr(i))
Next
'ソート
list.Sort()
'重複なしの場合は重複を削除する
If unique = 1 Then
	pre = list.Item(n)
	For i=n-1 to 0 step -1
	    If list.Item(i) = pre Then
	    	list.RemoveAt(i)
	    End If
		pre = list.Item(i)
	Next
End If
'降順の場合は逆順にする
If order = 1 Then
    list.Reverse()
End If
'改行(LF)で結合して文字列化
clip = Join(list.ToArray(), vbLf)
'クリップボードに設定
rc = Editor.SetClipboard(mode, clip)
'貼り付け
Editor.Paste(0)