質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

マクロ

定義された処理手続きに応じて、どのような一連の処理を行うのかを特定させるルールをマクロと呼びます。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

4回答

2912閲覧

Excel マクロが急に誤作動するようになった

nbotnk

総合スコア9

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

マクロ

定義された処理手続きに応じて、どのような一連の処理を行うのかを特定させるルールをマクロと呼びます。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

1クリップ

投稿2020/04/03 03:16

編集2020/04/08 05:58

これまで正常に作動していた差分チェックマクロが急に誤作動するようになり、原因が分からなくて
困っています。

<マクロの内容>
新旧2つの故障コードリストがあり、ワークシート1に新しいリスト、ワークシート2に古いリストが
記載されています。2つのリストの行数は同じではなく、新規コードの追加、既存原文の変更、既存
訳文の変更の可能性があります。

リストの構成
A列:コード、B列:原文、C列:訳文

  1. C列の訳文を比較し、差分(新出/変更)があれば、D列に「New」と表記

  データ数が多いので、配列を使用

  1. A列の訳文を比較し、差分があれば、コードを赤字に変更

  2. B列の原文を比較し、差分があれば、原文を青字に変更

  3. タイトル行を固定

実際のリストが公開できないため難しいかもしれませんが、誤作動を誘発している可能性のあるコードが
分かれば修正できるかもしれないので、それだけでも助かります。
また、誤作動の内容ですが、新出や変更でないものまで、Newとなったり、赤字/青字になったりする
ようになりました。ちなみに、今回、リストの全体的な修正があったため、どこかに誤作動の原因になる
変更があった可能性もありますが、基本的にリストの形式は同じです。

<実際のコード>
Sub KDVDB_DiffCheck()
Dim strProm As String
Dim ws1, ws2 As Worksheet

Set ws1 = Worksheets("New") Set ws2 = Worksheets("Old") Application.ScreenUpdating = False strProm = NoMtch(ws1.Cells(1, 3), ws2.Cells(1, 3)) Call CheckCode Call CheckSource Call Freeze_row Application.ScreenUpdating = True MsgBox "差分チェックの結果はシート『New』に表示されます。", Title:="処理完了", Buttons:=vbInformation

End Sub

Private Function NoMtch(ws1 As Range, ws2 As Range) As String

Dim i As Long Dim lngRows As Long Dim vntData() As Variant Dim dicIndex As Object Set dicIndex = CreateObject("Scripting.Dictionary") With ws2 lngRows = .Offset(Rows.Count - .Row).End(xlUp).Row - .Row If lngRows <= 0 Then NoMtch = "データがありません" GoTo Wayout End If vntData = .Offset(1).Resize(lngRows + 1).Value End With For i = 1 To lngRows dicIndex.Item(vntData(i, 1)) = Empty Next i With ws1 lngRows = .Offset(Rows.Count - .Row).End(xlUp).Row - .Row If lngRows <= 0 Then NoMtch = "データがありません" GoTo Wayout End If With .Offset(1).Resize(lngRows + 1) vntData = .Value End With End With For i = 1 To lngRows If Not dicIndex.Exists(vntData(i, 1)) Then With ws1.Offset(i) ws1.Offset(i, 1).Value = "New" End With End If Next i

Wayout:

Set dicIndex = Nothing

End Function

Sub CheckCode()
Dim strProm As String
Dim ws1, ws2 As Worksheet

Set ws1 = Worksheets("New") Set ws2 = Worksheets("Old") strProm = NoMtchC(ws1.Cells(1, 1), ws2.Cells(1, 1))

End Sub

Function NoMtchC(ws1 As Range, ws2 As Range) As String

Dim i As Long Dim lngRows As Long Dim vntData() As Variant Dim dicIndex As Object Set dicIndex = CreateObject("Scripting.Dictionary") With ws2 lngRows = .Offset(Rows.Count - .Row).End(xlUp).Row - .Row If lngRows <= 0 Then NoMtchC = "データがありません" GoTo Wayout End If vntData = .Offset(1).Resize(lngRows + 1).Value End With For i = 1 To lngRows dicIndex.Item(vntData(i, 1)) = Empty Next i With ws1 lngRows = .Offset(Rows.Count - .Row).End(xlUp).Row - .Row If lngRows <= 0 Then NoMtchC = "データがありません" GoTo Wayout End If With .Offset(1).Resize(lngRows + 1) vntData = .Value End With End With For i = 1 To lngRows If Not dicIndex.Exists(vntData(i, 1)) Then With ws1.Offset(i) .Font.Color = vbRed End With End If Next i

Wayout:

Set dicIndex = Nothing

End Function

Sub CheckSource()
Dim strProm As String
Dim ws1, ws2 As Worksheet

Set ws1 = Worksheets("New") Set ws2 = Worksheets("Old") strProm = NoMtchS(ws1.Cells(1, 2), ws2.Cells(1, 2))

End Sub

Function NoMtchS(ws1 As Range, ws2 As Range) As String

Dim i As Long Dim lngRows As Long Dim vntData() As Variant Dim dicIndex As Object Set dicIndex = CreateObject("Scripting.Dictionary") With ws2 lngRows = .Offset(Rows.Count - .Row).End(xlUp).Row - .Row If lngRows <= 0 Then NoMtchS = "データがありません" GoTo Wayout End If vntData = .Offset(1).Resize(lngRows + 1).Value End With For i = 1 To lngRows dicIndex.Item(vntData(i, 1)) = Empty Next i With ws1 lngRows = .Offset(Rows.Count - .Row).End(xlUp).Row - .Row If lngRows <= 0 Then NoMtchS = "データがありません" GoTo Wayout End If With .Offset(1).Resize(lngRows + 1) vntData = .Value End With End With For i = 1 To lngRows If Not dicIndex.Exists(vntData(i, 1)) Then With ws1.Offset(i) .Font.Color = vbBlue End With End If Next i

Wayout:

Set dicIndex = Nothing

End Function

Sub Freeze_row()

Worksheets("New").Activate
Rows(2).Select
ActiveWindow.FreezePanes = True
Range("A1").Select

End Sub

以上、よろしくお願いいたします。

<解決しました>

誤動作の原因が分かりました。
どう見ても同じなのに不一致、つまり差分箇所と判定されている箇所を
抜き出し、LEN関数で文字数を確認したところ、1文字違っていました。
一方のリストに余分な制御コードが含まれていたのです。
セル内の改行回数は同じであり、スペースもないので、その制御コードに
どのような機能があるのかは不明ですが、すべてのセルの制御コードを
削除した後、改めて差分チェックマクロを実行すると、正確な結果が得られました。

今後は、制御コードによる文字数の不一致にも対応できるようにコードを書き換えたいと
思います。ただし、

 Private Sub trim()
Dim c As Range
For Each c In Selection
c = WorksheetFunction.Clean(c)
Next c
End Sub

のような簡易なコードでは時間が結構かかったので、これを何とかしなくてはいけませんが。

回答、コメントをくださった方々、ありがとうございました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

重複まとめると、、これでよいのかな?

VBA

1Sub KDVDB_DiffCheck2() 2Dim ret As String 3ret = "" 4Call CheckSource2(ret) 5If ret <> "" Then MsgBox ret 6End Sub 7 8Sub CheckSource2(ret As String) 9Dim strProm As String 10Dim ws1 As Range, ws2 As Range 11Set ws1 = Worksheets("New").Cells(1, 1) 12Set ws2 = Worksheets("Old").Cells(1, 1) 13 14Application.ScreenUpdating = False 15 16Dim i As Long, j As Long 17Dim lngRows As Long 18Dim vntData() As Variant 19Dim dicIndex As Object 20 21Set dicIndex = CreateObject("Scripting.Dictionary") 22 23With ws2 24 lngRows = .Offset(Rows.Count - .Row).End(xlUp).Row - ws2.Row 25 If lngRows <= 0 Then 26 ret = "WS2データがありません" 27 Exit Sub 28 End If 29 vntData = .Offset(1).Resize(lngRows + 1).Value 30End With 31 32For i = 1 To lngRows 33 dicIndex.Item(vntData(i, 1)) = i 34Next i 35 36With ws1 37 lngRows = .Offset(Rows.Count - .Row).End(xlUp).Row - .Row 38 If lngRows <= 0 Then 39 ret = "WS1データがありません" 40 Exit Sub 41 End If 42 43 With .Offset(1).Resize(lngRows + 1) 44 vntData = .Value 45 End With 46End With 47 48For i = 1 To lngRows 49 If Not dicIndex.Exists(vntData(i, 1)) Then 50 'コードが見つからない 51 ws1.Offset(i, 3).Value = "New" 52 Else 53 'コードが見つかった 54 j = dicIndex.Item(vntData(i, 1)) 55 '原文比較 56 If ws1.Offset(i, 1).Value <> ws2.Offset(j, 1).Value Then 57 ws1.Offset(i, 1).Font.Color = vbBlue 58 End If 59 '訳文比較 60 If ws1.Offset(i, 2).Value <> ws2.Offset(j, 2).Value Then 61 ws1.Offset(i, 0).Font.Color = vbRed 62 End If 63 End If 64Next i 65 66Application.ScreenUpdating = True 67 68MsgBox "差分チェックの結果はシート『New』に表示されます。", Title:="処理完了", Buttons:=vbInformation 69 70End Sub 71 72

投稿2020/04/05 07:28

sinzou

総合スコア392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nbotnk

2020/04/07 07:00

ご回答ありがとうございます。 ご教示いただいたコードを試させていただきました。 変更された訳文のコードが赤字にり、Newが表示されない、 新出ではない原文が青字になる等、残念ながら、問題解決 には至りませんでした。 実際のデータを提供できない上、原因が分かっていないので 他の方に教えていただいたコードをそのまま使っても、すぐには解決 できないようです。 ご教示いただいたコードを参考にして動作確認をしながら、 原因を突き止めたいと思います。
guest

0

長々コードを貼るのではなく、1処理ずつ挙動確認して納得のいかない箇所のみを貼り付けて貰えると
回答しやすいです。

投稿2020/04/04 10:21

toppunobice0

総合スコア17

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nbotnk

2020/04/07 06:43

ご指摘の通りだと思います。正しい結果が得られない動作が多過ぎて納得のいかない箇所を特定できなかったので、コード全体を貼っていました。1処理ずつ動作確認してみます。
guest

0

誤動作ではなく、比較対象のシートの内容が変わったことによる正しい動作ではないですか?
誤動作と思っている"D列に「New」と設定する"、"コードを赤字に設定する"、"原文を青字に設定する"ところにbreak pointを設定した状態でマクロを起動して、何故設定するかを検証してはいかがでしょうか?

投稿2020/04/04 10:18

sage

総合スコア1216

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nbotnk

2020/04/07 06:40

ご回答ありがとうございます。 ご指摘の通りだと思うのですが、どこが変わったているのかが 分からないのです。見たところ、変わっているのはフォントだけで、 それを合わせても、これまで通りに正しく動作しないのです。 引き続き、検証してみます。
sage

2020/04/07 07:03

等しいと思っているのに違うと判定する(赤字になってしまう)行だけのサンプルデータを提供してもらえれば、誰かがその理由を検証できるかもしれません。
guest

0

ベストアンサー

配列とかdictionaryとか使っても、
セルの書式設定は結局セルを操作しないといけないんで、
どうなんでしょう?やってみないとわかりませんが。。。。(確かめる元気はないのですが^^;)

あと、セルの書式設定を個別にやっていくと、
大量のデータだと、
ファイルが無駄に大きくなって使いずらいかもしれません。
纏めて出来るところはまとめてやった方がいいと思います。

ExcelVBA

1Sub test() 2 Dim rngOld As Range 3 Dim rngNew As Range 4 5 Set rngOld = Worksheets("Old").UsedRange 6 Set rngNew = Worksheets("New").UsedRange 7 8 rngNew.FormatConditions.Delete 9 rngNew.Columns(1).FormatConditions.Add(Type:=xlExpression, Formula1:=GetFormula(rngOld, 2)).Font.Color = vbRed 10 rngNew.Columns(3).FormatConditions.Add(Type:=xlExpression, Formula1:=GetFormula(rngOld, 3)).Font.Color = vbBlue 11 rngNew.Columns(4).Formula = GetFormula(rngOld, 0) 12End Sub 13 14Function GetFormula(ByRef rngList As Range, ByVal ixCol As Long) As String 15 Const cFormula1 As String = "=INDEX(XXXX,MATCH($A1,YYYY,0),ZZZZ)<>TTTT" 16 Const cFormula2 As String = "=IF(COUNTIF(XXXX,YYYY),"""",""New"")" 17 Dim f As String 18 19 If ixCol > 0 Then 20 f = Replace(cFormula1, "XXXX", rngList.Address(, , , True)) 21 f = Replace(f, "YYYY", rngList.Columns(1).Address(, , , True)) 22 f = Replace(f, "ZZZZ", ixCol) 23 f = Replace(f, "TTTT", rngList(1, ixCol).Address(False, True)) 24 Else 25 f = Replace(cFormula2, "XXXX", rngList.Columns(1).Address(, , , True)) 26 f = Replace(f, "YYYY", rngList(1, 1).Address(False, True)) 27 End If 28 29 GetFormula = f 30End Function

投稿2020/04/04 03:28

mattuwan

総合スコア2136

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nbotnk

2020/04/07 06:33

ご回答ありがとうございます。 ご教示いただいたコードを試させていただきました。 新出ではないコードが赤字になる、原文ではなく訳文が青字になる、 Newが正確に表示されない(新出、変更された訳文セルの右隣り)等、 残念ながら、問題解決には至りませんでした。 実際のデータを提供できない上、原因が分かっていないので 他の方に教えていただいたコードをそのまま使っても、すぐには解決 できないようです。 ご教示いただいたコードを参考にして動作確認をしながら、 原因を突き止めたいと思います。
mattuwan

2020/04/07 07:10

所詮、手動ですることを自動化しただけですので、 シート上の設定や数式をみて微調整していただけたら、いいかと。 で、結果は間違ってるかもしれませんが、 処理は何秒ぐらいで終わります? 上手く設定出来れば処理の秒数はほぼほぼ変わらないかとは思いますが。
nbotnk

2020/04/07 07:27

処理は一瞬で終わりました。 今後のマクロ作成の際にも参考にさせていただきます。
mattuwan

2020/04/07 07:36

了解です。ありがとうございます。 シート上の位置が説明と微妙に違うのでしょうか? 数式を変更すれば行けると思いますが、 デバッグのしようがないので、ご了承願います。 あ、処理速度は現状のコードでも不満はなかったでした? なんだか、他の質問も読んでごっちゃにしてたかもです失礼しました。
nbotnk

2020/04/07 08:39

処理速度は現状のコードでも不満はなかったです。1秒ほどです。 これまでは正確な結果が得られていたので、まずは原因を突き止め、 その上で適切なコードが分からなかったら、改めて質問しようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問