0

I have a spreadsheet with a good amount of data (more than 100,000 rows with columns a-h).

I know twenty or more distinct values in Column F are wrong and I know what they should be. For example, every occurrence of "pif" should be "pig" and "coe" should be "cow", etc.

(Note that there are multiple incorrect values (i.e. multiple "pif"s) for each.)

I'm currently building a macro to go through and fix these individually, and that part works:

Sub FixColumnF()

ActiveSheet.Columns("F").Replace What:= _
        "pif", _
        Replacement:="pig", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:= _
        False, SearchFormat:=False, ReplaceFormat:=False
ActiveSheet.Columns("F").Replace What:= _
        "coe", _
        Replacement:="cow", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:= _
        False, SearchFormat:=False, ReplaceFormat:=False

...

End Sub

My problem is that column A is used to keep track of errors, one of which is an incorrect value in column F. How do I erase the value in column A to indicate there is no longer an error for each row where the value in column F is fixed?

I'm extremely new to vba, so any help would be very much appreciated!

ZX9
  • 898
  • 2
  • 16
  • 34
  • what value should col A cell contain? true or false or what? – ZAT Oct 20 '14 at 19:12
  • Actually all it has to do is empty the cell. But if others had a similar situation, they may want to change the value, so I didn't specify. – ZX9 Oct 21 '14 at 15:31

2 Answers2

1

There are two ways that I can think of.

Way 1

Use .Find/.FindNext to loop though all the cells which have say the word "pif". In that loop not only replace the word but also edit the value in Col A. For example (Untested)

Sub Sample()
    Dim oRange As Range, aCell As Range, bCell As Range
    Dim ws As Worksheet
    Dim SearchString As String, FoundAt As String

    On Error GoTo Whoa

    Set ws = Worksheets("Sheet1")
    Set oRange = ws.Columns(5) '<~~ Column 5

    SearchString = "pif"
    NewString = "pig"

    Set aCell = oRange.Find(What:=SearchString, LookIn:=xlValues, _
                LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
                MatchCase:=False, SearchFormat:=False)

    If Not aCell Is Nothing Then
        Set bCell = aCell

        '~~> Change value in Cell F
        aCell.Value = Replace(aCell.Value, SearchString, NewString)
        '~~> Change value in Cell A
        aCell.Offset(, -5).Value = "Rectified"

        Do
            Set aCell = oRange.FindNext(After:=aCell)

            If Not aCell Is Nothing Then
                If aCell.Address = bCell.Address Then Exit Do
                aCell.Value = Replace(aCell.Value, SearchString, NewString)
                aCell.Offset(, -5).Value = "Rectified"
            Else
                Exit Do
            End If
        Loop
    End If

    Exit Sub
Whoa:
    MsgBox Err.Description
End Sub

Way 2

Use Autofilter to filter Col F on the word "pif". Loop though all the cells in Col A and add the relevant message. Remove Autofilter and then run your original code (mentioned in your question) to do the replace in Col F. see THIS link on how to use Autofilter.

Community
  • 1
  • 1
Siddharth Rout
  • 147,039
  • 17
  • 206
  • 250
  • Tony's method was a little more streamlined, but I appreciate the detailed and timely response. – ZX9 Oct 21 '14 at 15:57
1

Siddharth posted his suggestions while I was testing/typing mine. My first suggestion is a simple variation of his first suggestion and offers no advantage that I can see. However, my second suggestion is different from either of his suggestions and may be appropriate.

You need to loop for each occurrence of "pif" and "coe" if you want to do something extra with each faulty value found. The code below shows how to replace every occurrence of "pif" by "pig" and then do something with column "A". If you like this technique, you would need to duplicate this code for "coe" and "cow".

Option Explicit
Sub ReplaceFaultyA()

  Dim Rng As Range

  ' It is best to avoid "ActiveSheet" in case the use has called the
  ' macro with the wrong worksheet active. Probably this is not likely
  ' in this case but I like to follow good practice even if it not not
  ' necessary
  With Worksheets("Data")

    Do While True

      ' Are you sure all your Find parameters are correct? For example,
      ' "LookAt:=xlPart" means than "pif" in the middle of a word will
      ' be replaced by "pig". "LookAt:=xlWhole" may better match your
      ' requirement. I suggest you look up the specification of Find
      ' and consider the implications of each parameter.
      Set Rng = .Columns("F").Find(What:="pif")
      If Rng Is Nothing Then
        ' No [more] occurrences of "pif" in column F
        Exit Do
      Else
        ' Occurrences of "pif" found in column F
        .Cells(Rng.Row, "F") = "pig"
        ' Amend column ""A" of Rng.Row as necessary
      End If
   Loop

  End With

End Sub

Duplication my loop and replacing "pif" and "pig" by "coe" and "cow" in the duplicate is probably the simpliest solution if there are only two replacements. However, if there are many replacements, the technique below may be a better choice.

In this code, I place the faulty values and the matching good values in arrays. With this approach, one block of replacement code can handle an indefinite number of replacements providing the action for column A is the same for each replacement.

Sub ReplaceFaultyB()

  Dim InxValue As Long
  Dim Rng As Range
  Dim ValueFaulty() As Variant
  Dim ValueGood() As Variant

  ' The code below assumes there same number of entries in both arrays.
  ' You can add extra entries to the two arrays as necessary.
  ' This assumes the action for column "A" is the same for each faulty value
  ValueFaulty = Array("pif", "coe", "appme")
  ValueGood = Array("pig", "cow", "apple")

  With Worksheets("Data")

    For InxValue = LBound(ValueFaulty) To UBound(ValueFaulty)

      Do While True
        Set Rng = .Columns("F").Find(What:=ValueFaulty(InxValue))
        If Rng Is Nothing Then
          ' No [more] occurrences of this faulty value in column F
          Exit Do
        Else
          ' Occurrences of faulty value found in column F
          .Cells(Rng.Row, "F") = ValueGood(InxValue)
          ' Amend column ""A" of Rng.Row as necessary
        End If
     Loop

   Next InxValue

  End With

End Sub
Tony Dallimore
  • 12,335
  • 7
  • 32
  • 61
  • The second solution works like a charm and is the most elegant, especially considering that I have 20 or more replacements to make. My only suggestion is to put "With ActiveSheet" by default instead of an arbitrary name; as a noobie it took me a second to fix. Thanks so much! (Sorry I don't have the rep to vote you up!) – ZX9 Oct 21 '14 at 15:54
  • @ZX9 I am pleased you liked the second technique. I use variations of it frequently. – Tony Dallimore Oct 21 '14 at 16:34
  • @ZX9 Very occasionally you want the user to be able to select the target worksheet by selecting it before running a macro. In such cases `ActiveSheet` is appropriate. More usually, macros are designed for specific worksheets. I know from bitter experience that you cannot guarantee the user will have selected the correct worksheet. If you return to a macro in a few months, will you remember which worksheet it its target? I find `Worksheets("Xxxxx")` with an appropriate "Xxxxx", the right solution 99 times out of a 100. Sorry that I did not make clear that it is not always the right solution. – Tony Dallimore Oct 21 '14 at 16:37
  • That makes sense. I deal with new worksheets everyday, so it would be a pain to change the macro every time. No problem, really; thanks for your help again. – ZX9 Oct 21 '14 at 18:43