校閲ツールで修正した結果の履歴
昨日は、Excel で Word のように校閲するサブプロシージャを、ユーザーフォームに組み込んでみました。
これについて、はけたさんから「履歴を残してはどうか」とのご提案を頂きましたので、挑戦してみました。
今回はとりあえず、履歴管理用のシートを、校閲を行うブック内に作成することにしました。シートを作成するタイミングは、実際に文字列を置換するタイミングとします。そこで、作者であるthomさんには失礼して、Class_Initializeに少し追記しました。
Private Sub Class_Initialize() ReDim colorTextArray(0) ' 以下、追記箇所。 Dim Ws As Worksheet For Each Ws In Worksheets If Ws.Name = HistorySheetName Then Exit Sub End If Next Dim CurrentSheet As Worksheet Set CurrentSheet = ActiveSheet Sheets.Add After:=Sheets(Sheets.Count) ActiveSheet.Name = HistorySheetName Call MakeHistoryTable CurrentSheet.Select End Sub
↓ 履歴記録用シート作成(クラスモジュール内)
Private Sub MakeHistoryTable() Cells(1, 1) = "シート名" Cells(1, 2) = "対象セル" Cells(1, 3) = "修正日" Cells(1, 4) = "修正前" Cells(1, 5) = "修正後" ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A$1:$E$1"), , xlYes).Name = "履歴テーブル" With ActiveSheet.ListObjects(1) .TableStyle = "TableStyleLight13" .ShowAutoFilterDropDown = False End With End Sub
次いで、標準モジュールに以下を追記します。
Public Const HistorySheetName As String = "★校閲履歴"
↓ 履歴記録用プロシージャがこちらになります。
Sub RecordHistory(target_range As Range, original_word As String, correct_word As String) Dim HistoryTable As ListObject Set HistoryTable = Sheets(HistorySheetName).ListObjects(1) Dim AddRowIndex As Long On Error Resume Next AddRowIndex = HistoryTable.DataBodyRange.Rows.Count + 2 If AddRowIndex = 0 Then AddRowIndex = 2 With Sheets(HistorySheetName) .Cells(AddRowIndex, 1) = ActiveSheet.Name .Cells(AddRowIndex, 2) = target_range.Address(False, False) .Cells(AddRowIndex, 3) = Date .Cells(AddRowIndex, 4) = original_word .Cells(AddRowIndex, 5) = correct_word End With End Sub
あとは、修正実行ボタンに組み込むだけです。
Private Sub CorrectButton_Click() Dim r As Range For Each r In Selection Call CorrectWord(r, TextBox1.Value, TextBox2.Value) ' ↓ この一行を追加。 Call RecordHistory(r, TextBox1.Value, TextBox2.Value) End If Next TextBox1.Value = "" TextBox2.Value = "" TextBox1.SetFocus End Sub
できた!・・・あれ?関係ないセルまで修正が行われたことになっている。そう、これでは修正があってもなくても、選択範囲分だけ記録されてしまうのです。さて、どうしたものか・・・。
そこで、これまた失礼して、thomさんに作成していただいたサブプロシージャを、Boolean型のファンクションプロシージャに変更しました。何某かの修正が行われた場合、Trueを返します。
※内容はほぼ一緒で、最後に数行追加しています。
Function CorrectWord( _ target_range As Range, _ original_word As String, _ Optional corrected_word As String = "") As Boolean '以下でCellTextを実際の文字数よりも1つ多く確保しているのは、 '空白セルを選んだときにインデックスエラーを回避するのと、 'セルの内容が置換対象文字そのものだった場合に文字単位の 'ヒットカウント(charPointer)が上手く機能しないトラブルを '回避するための苦肉の策。 'なお、多めに確保したCellTextは中身が初期状態(vbNullString) 'なので動作に悪影響を与えない。 ReDim CellText(1 To Len(target_range.Value) + 1) '文字ごとにステータスを登録するフェーズ Dim i As Long For i = 1 To Len(target_range.Value) CellText(i).Text = Mid(target_range.Value, i, 1) CellText(i).State.Strikethrough = target_range.Characters(i, 1).Font.Strikethrough CellText(i).State.Replaced = target_range.Characters(i, 1).Font.Color = CorrectedWordColor Next 'original_wordの一致を一文字ずつ探すフェーズ Dim charPointer As Long: charPointer = 1 Dim charLocationStore As Collection: Set charLocationStore = New Collection Dim n As Long: n = 1 Do While n < UBound(CellText) If Not CellText(n).State.Strikethrough Then If Mid(original_word, charPointer, 1) = CellText(n).Text Then charPointer = charPointer + 1 charLocationStore.Add n Else charPointer = 1 Set charLocationStore = New Collection End If If charPointer > Len(original_word) Then Dim t For Each t In charLocationStore CellText(t).State.Strikethrough = True Next CellText(n).State.InsertPoint = True End If End If n = n + 1 Loop 'セルに出力するためにColorfulStringObjectを構築するフェーズ Dim CSO As ColorfulStringObject: Set CSO = New ColorfulStringObject Dim j As Long For j = LBound(CellText) To UBound(CellText) Dim col As XlRgbColor If CellText(j).State.Strikethrough Then col = OriginalWordColor ElseIf CellText(j).State.Replaced Then col = CorrectedWordColor Else col = rgbBlack End If CSO.AddText CellText(j).Text, col, CellText(j).State.Strikethrough If CellText(j).State.InsertPoint Then CSO.AddText corrected_word, CorrectedWordColor, False End If Next '今回の追記箇所 Dim BeforeString As String BeforeString = target_range.Value '一気にセル書き出し CSO.WriteToCell target_range '今回の追記箇所 If target_range.Value <> BeforeString Then CorrectWord = True Else CorrectWord = False End If End Function
↓ 修正実行ボタンは、このように変更しました。
Private Sub CorrectButton_Click() Dim r As Range For Each r In Selection ' 今回の変更箇所 If CorrectWord(r, TextBox1.Value, TextBox2.Value) = True Then Call RecordHistory(r, TextBox1.Value, TextBox2.Value) End If Next TextBox1.Value = "" TextBox2.Value = "" TextBox1.SetFocus End Sub
↓ 結果、修正箇所のみ、履歴テーブルに反映できました。
今回はここまでとしますが、いずれ修正確定も履歴の対象としたり、履歴テーブルの結果からUNDOするような仕掛けにも挑戦してみようと思います。
参考まで。