以前公開していたものはそれ単品では動作しない形式だったので、
必要な関数なども併せてフルバージョンとして置いておきます。
個人的に作成・利用をしているマクロで十分なデバッグが行われているとは言えません。
また処理対象を直接編集・保存している為、処理後に元に戻すことができません。
こういった点を理解した上、自己責任での利用をお願いします。
GrepAndReplace.vbs
'Grep結果を基に置換を行うマクロ
'
'【詳細】
'サクラエディタのGrep結果を基に文字列の置換を行います。
'置換の対象はGrep結果に載っているファイル&行だけです。
'置換文字列の指定はGrep結果の1行目に下記のフォーマットで記入してください。
'置換前後の文字列に「タブ」や「改行」は指定できません。
'【フォーマット】
'置換前文字列[tab]置換後文字列
'【例】"あいうえお"を"かきくけこ"に置換する場合
'あいうえお かきくけこ
'---------------------------------------------------------------------
'サクラエディタの検索パラメータ
Const OPT_WORD = 1 '単語単位で探す(W)
Const OPT_DIFF = 2 '英大文字と小文字を区別する(C)
Const OPT_RE = 4 '正規表現(E)
Const OPT_MSG = 8 '見つからないときにメッセージを表示(M)
Const OPT_DCLS = 16 '検索ダイアログを自動的に閉じる(L)
Const OPT_LOOP = 32 '先頭(末尾)から再検索する(Z)
Const OPT_CB = 64 'クリップボードから貼り付ける(T)
Const OPT_TGT = 128 '0:ファイル全体(O),1:選択範囲(S)
'置換処理を行うStrategy
'Publicで宣言されている部分の処理を差し替えることで、
'Grep結果に対する様々な処理を実装することができます。
Class Strategy
Private lngSize
Private strBefore
Private strAfter
Private lngOption
Private strPreviousPath
Private strErrMessage
'コンストラクタ
Private Sub Class_Initialize()
End Sub
'デストラクタ
Private Sub Class_Terminate()
End Sub
'初期化処理
Public Function initialize()
initialize = False
'1:選択範囲(S) + '検索ダイアログを自動的に閉じる(L) + '英大文字と小文字を区別する(C)
lngOption = OPT_TGT + OPT_DCLS + OPT_DIFF
lngSize = 0
strPreviousPath = ""
strErrMessage = ""
Dim strReplaceStringArray
strReplaceStringArray = Split(getString(Editor.GetLineStr(1)), vbTab)
If UBound(strReplaceStringArray) <> 1 Then
'置換前後の文字列が正しく設定されていない場合は処理しない
strErrMessage = "置換前後の文字列が正しく設定されていません。" & vbCrLf & "処理を終了します。"
Else
strBefore = strReplaceStringArray(0)
strAfter = strReplaceStringArray(1)
initialize = True
End If
End Function
'前処理
Public Function execPreProc()
execPreProc = True
End Function
'処理
Public Function exec(ByRef objGrepResult)
With objGrepResult
If strPreviousPath <> .strFilePath Then
If strPreviousPath <> "" Then
Call Editor.FileSave()
Call Editor.FileClose()
End If
Call Editor.FileOpen(.strFilePath)
End If
If replaceLine(.lngRow, strBefore, strAfter) Then
lngSize = lngSize + 1
End If
strPreviousPath = .strFilePath
End With
exec = True
End Function
'後処理
Public Sub execPostProc()
Call Editor.FileSave()
Call Editor.FileClose()
End Sub
'マクロ名
Public Function getTitle()
getTitle = "GrepAndReplace"
End Function
'処理開始時メッセージ
Public Function getNoticeMessage()
getNoticeMessage = _
"Grep結果に挙がっている全てのファイル&行に対し置換を行います。" & vbCrLf & _
"Grep結果が自動的に閉じられますので、Grep結果を残したい場合は事前に保存をしてください。" & vbCrLf & _
"また実行時にはGrep結果以外のファイルは全て閉じてください。" & vbCrLf & _
vbCrLf & _
"置換前文字列:""" & strBefore & """" & vbCrLf & _
"置換後文字列:""" & strAfter & """"
End Function
'処理終了時メッセージ
Public Function getEndMessage()
getEndMessage = lngSize & "件置換しました。"
End Function
'エラー時メッセージ
Public Function getErrMessage()
getErrMessage = strErrMessage
End Function
Public Sub setErrMessage(ByRef strArg)
strErrMessage = strArg
End Sub
'指定行のみを置換
Private Function replaceLine(ByRef lngRow, ByRef strBfr, ByRef strAft)
replaceLine = False
Dim lngR
Dim strOrgLine
With Editor
Call .Jump(lngRow, 1)
strOrgLine = .GetLineStr(lngRow)
Call .GoLineTop(1)
Call .BeginSelect()
Call .Jump(lngRow + 1, 1)
If .GetLineCount(0) <> lngRow Then
Call .GoLineTop(1)
Call .Left_Sel()
End If
Call .ReplaceAll(strBfr, strAft, lngOption)
If strOrgLine = .GetLineStr(lngRow) Then
replaceLine = False
Else
replaceLine = True
End If
End With
End Function
End Class
'ここから下は流用可能なロジック
'---------------------------------------------------------------------
Call manageMain()
'メイン処理の実行
Sub manageMain()
'Strategyのインスタンス生成
Dim objStrategy: Set objStrategy = New Strategy
'初期化処理
If objStrategy.initialize() = False Then
'初期化処理に失敗した場合は処理終了
MsgBox objStrategy.getErrMessage()
Set objStrategy = Nothing
Exit Sub
End If
'処理開始可否確認
Dim objDialog: Set objDialog = CreateObject("WScript.Shell")
Dim lngRtn: lngRtn = objDialog.Popup(objStrategy.getNoticeMessage(), 0, objStrategy.getTitle(), 1)
If lngRtn = 1 Then
If execMain(objStrategy) Then
'正常に処理した場合
MsgBox objStrategy.getEndMessage()
Else
'処理中断した場合
MsgBox objStrategy.getErrMessage()
End If
Else
MsgBox "処理を中止しました。"
End If
Set objDialog = Nothing
Set objStrategy = Nothing
End Sub
'メイン処理
Function execMain(Byref objStrategy)
execMain = False
'Grepされたフォルダのパスを取得
Dim strFolderPath: strFolderPath = getFolderPath()
If strFolderPath = "" Then
Call objStrategy.setErrMessage("Grep結果ファイルが想定外のフォーマットです。")
Exit Function
End If
'Grep結果の取得
Dim objGrepResults: objGrepResults = getGrepResults(strFolderPath)
'Grep結果のファイルを閉じる
Editor.FileClose()
'前処理
If objStrategy.execPreProc() Then
'前処理が正常な場合のみ実行
Dim blnErr: blnErr = False
Dim lngIu: lngIu = UBound(objGrepResults)
Dim lngI
For lngI = 0 To lngIu
'本処理
If objStrategy.exec(objGrepResults(lngI)) = False Then
'処理が正常終了しなかった場合は終わり
blnErr = True
Exit For
End If
Next
If blnErr = False Then
execMain = True
End If
End If
'後処理
Call objStrategy.execPostProc()
End Function
'対象ファイルのパスと行を全て取得する。
Function getGrepResults(Byref strFolderPath)
Dim lngRu: lngRu = Editor.GetLineCount(0)
Dim lngR
Dim lngI: lngI = -1
Dim objGrepResults(): Redim objGrepResults(lngRu)
Dim strLine
For lngR = lngRu To 1 Step -1
strLine = getLine(lngR)
If beginWith(strLine, strFolderPath) Then
lngI = lngI + 1
Set objGrepResults(lngI) = getGrepResult(strLine)
End If
Next
Redim Preserve objGrepResults(lngI)
getGrepResults = objGrepResults
End Function
'対象ファイルのパスと行を取得する。
Function getGrepResult(ByRef strArgLine)
Dim objGrepResult: Set objGrepResult = New GrepResult
With objGrepResult
.strLine = strArgLine
.strFilePath = getFilePath(strArgLine)
.lngRow = getRow(strArgLine)
.lngCol = getCol(strArgLine)
End With
Set getGrepResult = objGrepResult
Set objGrepResult = Nothing
End Function
'Grep結果から行を取得する。
Function getLine(ByRef lngR)
getLine = getString(Editor.GetLineStr(lngR))
End Function
'末尾の改行を削除した文字列を取得する。
Function getString(ByRef strLine)
If endWith(strLine, vbCrLf) Then
getString = Left(strLine, Len(strLine) - Len(vbCrLf))
ElseIf endWith(strLine, vbCr) Then
getString = Left(strLine, Len(strLine) - Len(vbCr))
ElseIf endWith(strLine, vbLf) Then
getString = Left(strLine, Len(strLine) - Len(vbLf))
Else
getString = strLine
End If
End Function
'Grep結果から対象フォルダを取得する。
Function getFolderPath()
Const STR_FOLDER_PREFIX = "フォルダ "
getFolderPath = ""
Dim lngRu: lngRu = Editor.GetLineCount(0)
Dim lngR
Dim strLine
For lngR = 1 To lngRu
strLine = getLine(lngR)
If beginWith(strLine, STR_FOLDER_PREFIX) Then
getFolderPath = Mid(strLine, Len(STR_FOLDER_PREFIX) + 1)
Exit Function
End If
Next
End Function
'strArg0がstrArg1で始まる文字列か。
Function beginWith(ByRef strArg0, ByRef strArg1)
beginWith = False
If Len(strArg0) < Len(strArg1) Then
Exit Function
End If
If InStr(1, strArg0, strArg1) = 1 Then
beginWith = True
End If
End Function
'strArg0がstrArg1で終わる文字列か。
Function endWith(ByRef strArg0, ByRef strArg1)
endWith = False
If Len(strArg0) < Len(strArg1) Then
Exit Function
End If
If Right(strArg0, Len(strArg1)) = strArg1 Then
endWith = True
End If
End Function
'Grep結果からファイルのパスを取得する。
Function getFilePath(ByRef strArgLine)
getFilePath = ""
Dim lngPlPos: lngPlPos = getPlPos(strArgLine)
Dim strPath: strPath = Left(strArgLine, lngPlPos - 1)
getFilePath = strPath
End Function
'Grep結果から行を取得する。
Function getRow(ByRef strArgLine)
getRow = 0
Dim lngPlPos: lngPlPos = getPlPos(strArgLine)
Dim lngCmmPos: lngCmmPos = getCmmPos(strArgLine)
Dim strRow: strRow = Mid(strArgLine, lngPlPos + 1, lngCmmPos - lngPlPos - 1)
getRow = CLng(Trim(strRow))
End Function
'Grep結果から列を取得する。
Function getCol(ByRef strArgLine)
getCol = 0
Dim lngCmmPos: lngCmmPos = getCmmPos(strArgLine)
Dim lngPrPos: lngPrPos = getPrPos(strArgLine)
Dim strCol: strCol = Mid(strArgLine, lngCmmPos + 1, lngPrPos - lngCmmPos - 1)
getCol = CLng(Trim(strCol))
End Function
'"("の位置を取得
Function getPlPos(ByRef strArgLine)
getPlPos = -1
Dim lngCrnPos: lngCrnPos = InStr(3, strArgLine, ":")
Dim lngP
Dim lngPlPos
For lngP = lngCrnPos To 3 Step -1
If Mid(strArgLine, lngP, 1) = "(" Then
lngPlPos = lngP
Exit For
End If
Next
getPlPos = lngPlPos
End Function
'","の位置を取得
Function getCmmPos(ByRef strArgLine)
getCmmPos = -1
Dim lngPlPos: lngPlPos = getPlPos(strArgLine)
Dim lngCmmPos: lngCmmPos = InStr(lngPlPos, strArgLine, ",")
getCmmPos = lngCmmPos
End Function
'")"の位置を取得
Function getPrPos(ByRef strArgLine)
getPrPos = -1
Dim lngCmmPos: lngCmmPos = getCmmPos(strArgLine)
Dim lngPrPos: lngPrPos = InStr(lngCmmPos, strArgLine, ")")
getPrPos = lngPrPos
End Function
Class GrepResult
Public strLine
Public strFilePath
Public lngRow
Public lngCol
End Class
0 件のコメント:
コメントを投稿