Найти и заменить цикл в Excel VBA
Я пытаюсь найти все значения в столбце W, которые содержат двоеточие, удалить двоеточие значения в этой ячейке и отметить XID в столбце A той же строки. Затем посмотрите, есть ли экземпляры значения в строках в столбцах CT и CU в строках с этим XID. Если в столбцах CT & CU есть какие-либо экземпляры, также удалите указанное двоеточие.
Что касается столбцов CT и CU, так это то, что в строках есть другие двоеточия, поэтому конкретное двоеточие необходимо удалить.
Пример: скажем, столбец W содержит "Меньше, чем минимум", и в той же строке XID в строке A будет "562670-6". Теперь, когда цикл отметил XID, в котором есть двоеточие (в данном случае "Less: Than Minimum"), меньший цикл внутри большого цикла будет просматривать все ячейки в столбцах CT & CU, которые имеют одинаковый XID. в столбце A найдите ячейки, которые содержат "Меньше: чем минимум" (на фото это будет ячейка CT2, в которой содержится "PROP: МЕНЬШЕ, ЧЕМ МИНИМУМ: ТАМ БУДЕТ...") и удалите двоеточие (таким образом это закончилось бы тем, что "ПРОП: МЕНЬШЕ, ЧЕМ МИНИМУМ: ТАМ БУДЕТ.....").
Поскольку в каждой ячейке столбцов CT & CU есть несколько двоеточий, моя идея состоит в том, чтобы искать ":Less: Than Minimum:", поскольку в начале и конце этой строки всегда будет двоеточие.
Я пытался выполнить эту задачу и дошел до этой точки
Option Explicit
Public Sub colonCheck()
Dim rng As Range, aCell As Range, bCell As Range, uRng As Range, uCell As Range
Dim endRange As Long
Dim opName As String, opName2 As String
Dim xid As String
endRange = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
Set rng = ActiveSheet.Range("W1:W" & endRange)
Set aCell = rng.Find(What:=":", LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bCell = aCell
opName = ":" & aCell.Value & ":"
'Type mismatch on rng = Replace(rng, ":", "")
rng = Replace(rng, ":", "")
aCell = rng
'set corrected value (sans-colon) to opName2
opName2 = aCell.Value
xid = ActiveSheet.Range("A" & aCell.Row).Value
'Whatever we add here we need to repeat in the if statement after do
'We have the option name and the xid associated with it
'Now we have to do a find in the upcharges column to see if we find the opName
'Then we do an if statement and only execute if the the Column A XID value matches
'the current xid value we have now
Set uRng = ActiveSheet.Range("W2:W" & endRange)
Set uCell = uRng.Find(What:=opName, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not uCell Is Nothing And ActiveSheet.Range("A" & uCell.Row).Value = xid Then
uRng = Replace(uRng, opName, opName2)
uCell = uRng
End If
'Above code was added
Do
Set aCell = rng.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
'Repeat above code in here so it loops
opName = ":" & aCell.Value & ":"
rng = Replace(rng, ":", "")
aCell = rng
'set corrected value (sans-colon) to opName2
opName2 = aCell.Value
xid = ActiveSheet.Range("A" & aCell.Row).Value
'Whatever we add here we need to repeat in the if statement after do
'We have the option name and the xid associated with it
'Now we have to do a find in the upcharges column to see if we find the opName
'Then we do an if statement and only execute if the the Column A XID value matches
'the current xid value we have now
Set uRng = ActiveSheet.Range("W2:W" & endRange)
Do
Set uCell = uRng.FindNext(After:=uCell)
If Not uCell Is Nothing Then
Set uCell = uRng.Find(What:=opName, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not uCell Is Nothing And ActiveSheet.Range("A" & uCell.Row).Value = xid Then
uRng = Replace(uRng, opName, opName2)
uCell = uRng
End If
Else
Exit Do
End If
Loop
'Above code was added
Else
Exit Do
End If
Loop
End If
End Sub
Я получаю ошибку несоответствия типов в строке
rng = Replace(rng, ":", "")
Я наткнулся на ответ на этот вопрос, в котором говорилось, что "Замена работает только со строковыми переменными", поэтому я думаю, что это может быть причиной проблемы?
Как я могу отредактировать приведенный выше код, чтобы выполнить то, что я хочу сделать? Есть ли другой подход (который все еще осуществляется через VBA).
Обновление / Пересмотр
Итак, я немного продвинулся в том, что смог успешно найти и заменить первый экземпляр двоеточия, опция "Меньше, чем минимум" заменена на "Меньше, чем минимум" в столбцах W и CT. Проблема, с которой я сталкиваюсь сейчас, состоит в том, чтобы заставить циклы Do работать правильно. Вот к чему я пришел (я включил несколько комментариев в код, чтобы, надеюсь, помочь в руководстве тем, кто хочет попробовать и помочь)
Option Explicit
Public Sub MarkDuplicates()
Dim rng As Range, aCell As Range, bCell As Range, uRng As Range, uCell As Range, sCell As Range
Dim endRange As Long
Dim opName As String, opName2 As String
Dim xid As String
endRange = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
Set rng = ActiveSheet.Range("W1:W" & endRange)
Set aCell = rng.Find(What:=":", LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
'bCell now holds the original cell that found
Set bCell = aCell
'Add colon to beginning and end of string to ensure we only find and replace the right portion over in upcharge column
opName = ":" & aCell.Value & ":"
'Correct the value in column W
aCell = Replace(ActiveSheet.Range("W" & aCell.Row).Value, ":", "")
'Set corrected value (sans-colon) to opName2 and add colon to beginning and end of string
opName2 = ":" & aCell.Value & ":"
'Note the XID of the current row so we can ensure we look for the right upcharge
xid = ActiveSheet.Range("A" & aCell.Row).Value
'We have the option name and the xid associated with it
'Now we have to do a find in the upcharges column to see if we find the opName
'Then we do an if statement and only execute if the the Column A XID value matches
'the current xid value we have now
Set uRng = ActiveSheet.Range("CT2:CU" & endRange)
'Set uCell to the first instance of opName
Set uCell = uRng.Find(What:=opName, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'If there is an instance of opName and uCell has the value check if the xid matches to ensure we're changing the right upcharge
If Not uCell Is Nothing And ActiveSheet.Range("A" & uCell.Row).Value = xid Then
Set sCell = uCell
'If so then replace the string in the upcharge with the sans-colon version of the string
uCell = Replace(ActiveSheet.Range("CT" & uCell.Row).Value, opName, opName2)
End If
Do
'>>>The .FindNext here returns Empty<<<
Set aCell = rng.FindNext(After:=aCell)
If Not aCell Is Nothing Then
'if aCell and bCell match then we've cycled through all the instances of option names with colons so we exit the loop
If aCell.Address = bCell.Address Then Exit Do
'Add colon to beginning and end of string to ensure we only find and replace the right portion over in upcharge column
opName = ":" & aCell.Value & ":"
'Correct the value in column W (Option_Name)
aCell = Replace(ActiveSheet.Range("W" & aCell.Row).Value, ":", "")
'Set corrected value (sans-colon) to opName2 and add colon to beginning and end of string
opName2 = ":" & aCell.Value & ":"
'Note the XID of the current row so we can ensure we look for the right upcharge
xid = ActiveSheet.Range("A" & aCell.Row).Value
Do
Set uCell = uRng.FindNext(After:=uCell)
If Not uCell Is Nothing Then
'Check to make sure we haven't already cycled through all the upcharge instances
If uCell.Address = sCell.Address Then Exit Do
'Correct the value in column CT
uCell = Replace(ActiveSheet.Range("CT" & uCell.Row).Value, opName, opName2)
Else
Exit Do
End If
Loop
Else
Exit Do
End If
Loop
End If
End Sub
Как я прокомментировал в коде, я, кажется, связал себя в самом начале первого цикла Do Loop в строке
Do
'>>>The .FindNext here returns Empty<<<
Set aCell = rng.FindNext(After:=aCell)
.FindNext(After:=aCell)
По какой-то причине возвращается пустым, хотя я поместил двоеточие в ячейках с надписью "Отгрузка: - ....." и "SHOP: Отгрузка: - ....."
Любая идея почему или любая идея, как я могу это исправить?
3 ответа
Вы должны перебрать все клетки следующим образом:
For i = 1 To endRange
If Not aCell Is Nothing Then
opName = ":" & aCell.Value & ":"
aCell = Replace(ActiveSheet.Range("W" & aCell.Row).Value, ":", "")
opName2 = ":" & aCell.Value & ":"
xid = ActiveSheet.Range("A" & aCell.Row).Value
Set uRng = ActiveSheet.Range("CT2:CU" & endRange)
Set uCell = uRng.Find(What:=opName, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not uCell Is Nothing And ActiveSheet.Range("A" & uCell.Row).Value = xid Then
Set sCell = uCell
uCell = Replace(ActiveSheet.Range("CT" & uCell.Row).Value, opName, opName2)
End If
Next i
Я здесь просто счетчик, но вы можете использовать его как индекс строки:
Cells(i, "W") 'Cells(RowIndex, ColumnIndex) works great for single cells
Если вы хотите сделать больше в этом цикле, я бы также порекомендовал написать функции, которые вы можете вызывать с определенными параметрами.
Например (не очень хороший):
Function Renaming(Cell as Range)
Renaming = ":" Cell.Value ":"
End Function
Тогда вы можете вызвать функцию:
Call Renaming(aCell)
Я верю, что это немного тебе поможет.
Также вам не нужно указывать диапазон от aCell до bCell, так как он останется прежним. Если вы хотите сохранить значение где-нибудь, вам нужно объявить bCell как String, а затем сделать следующее:
bCell = aCell.Value
В противном случае эта часть кода довольно бесполезна, поскольку диапазон вашей ячейки не изменится, пока вы не закончили с вашим кодом.
Я новичок в VBA, но если какой-то код работает для вас, не стесняйтесь его использовать. Если есть предложения по улучшению кода, я бы с удовольствием прочитал комментарии:)
С некоторой пробой и ошибкой (и помощью @Kathara в указании на несколько слабых мест для очистки и предложении пути моего цикла) я, наконец, пришел к полностью работающему решению. Однако вместо того, чтобы циклически проходить по столбцу параметров и затем циклически проходить по столбцам критериев пополнения 1 и критериев пополнения 2 каждый раз, когда я сталкиваюсь с именем варианта с двоеточием, я использовал Find()
метод, так как я знаю, что каждый раз, когда я нахожу первое значение в верхней части столбца Имя параметра, значение будет одним из первых, которые будут найдены, если смотреть сверху вниз из столбцов дополнительной платы. Я также решил разделить uRng на два диапазона (uRng1 для критериев пополнения 1 и uRng2 для критериев пополнения 2) и проверять uRng2 сразу после каждой проверки uRng1, гарантируя, что я заменю имя опции в обоих столбцах. Я удалил переменные диапазона bCell & sCell, потому что, как указала Катара, они не являются жизненно важными для Sub. На самом деле, там были просто примеры, из которых я делал свой Sub, так вот откуда они (хороший глаз Катхара!). С помощью @andrewf я также понял, что не Replace()
работать правильно, так как я предоставлял диапазон внутри него, а не значение текущей ячейки этого диапазона. Наконец, прежде чем кто-то скажет, что я должен был сохранить Option Compare Text
В своем коде я понял, что он не будет работать позже в моем общем проекте, так как это одна подпрограмма, которая будет объединена примерно с 10 другими для создания моего конечного продукта. Итак, вместо этого я упал на UCase()
функция, которая отвечает всем требованиям именно для того, что мне нужно сделать. Итак, без лишних слов, ниже завершен код. Если кто-то в будущем сможет получить хоть какие-то знания или использовать какой-то лакомый кусочек из моей работы, чтобы помочь им, я буду счастлив, зная, что смог помочь любым способом.
Sub dupOpCheck()
Dim rng As Range, aCell As Range, uRng1 As Range, uRng2 As Range, uCell As Range
Dim endRange As Long
Dim opName As String, opName2 As String
Dim xid As String
endRange = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
Set rng = ActiveSheet.Range("W1:W" & endRange)
Set aCell = rng.Find(What:=":", LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
'Add colon to beginning and end of string to ensure we only find and replace the right
'portion over in upcharge column
opName = ":" & aCell.Value & ":"
'Correct the value in column W
aCell = Replace(ActiveSheet.Range("W" & aCell.Row).Value, ":", "")
'Set corrected value (sans-colon) to opName2 and add colon to beginning and
'end of string
opName2 = ":" & aCell.Value & ":"
'Note the XID of the current row so we can ensure we look for the right upcharge
xid = ActiveSheet.Range("A" & aCell.Row).Value
'We have the option name and the xid associated with it
'Now we have to do a find in the upcharges column to see if we find the opName
'Then we do an if statement and only execute if the the Column A XID value matches
'the current xid value we have now
Set uRng1 = ActiveSheet.Range("CT1:CT" & endRange)
Set uRng2 = ActiveSheet.Range("CU1:CU" & endRange)
'Convert uRng1 & uRng2 to all uppercase just to make sure they will be detected when using Find
'Set uCell to the first instance of opName
Set uCell = uRng1.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'If there is an instance of opName and uCell has the value check if the xid matches
'to ensure we 're changing the right upcharge
If Not uCell Is Nothing Then
If ActiveSheet.Range("A" & uCell.Row).Value = xid Then
'If so then replace the string in the upcharge with the sans-colon version of the string
uCell = Replace(UCase(ActiveSheet.Range("CT" & uCell.Row).Value), UCase(opName), UCase(opName2))
End If
'Now we look in upcharge_criteria_2 column
Set uCell = uRng2.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not uCell Is Nothing Then
If ActiveSheet.Range("A" & uCell.Row).Value = xid Then
'If so then replace the string in the upcharge with the sans-colon version of the string
uCell = Replace(UCase(ActiveSheet.Range("CU" & uCell.Row).Value), UCase(opName), UCase(opName2))
End If
End If
Else
'Now we just look in upcharge_criteria_2 column since we didn't find an instance in upcharge_criteria_1 column
Set uCell = uRng2.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not uCell Is Nothing Then
If ActiveSheet.Range("A" & uCell.Row).Value = xid Then
'If so then replace the string in the upcharge with the sans-colon version of the string
uCell = Replace(UCase(ActiveSheet.Range("CU" & uCell.Row).Value), UCase(opName), UCase(opName2))
End If
End If
End If
Do
'Check for Options
'Instead of After:=aCell we have to make a start of before aCell or maybe just start back at row 1?
'What:=":", After:=aCell
Set aCell = rng.Find(What:=":", LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
'Add colon to beginning and end of string to ensure we only find and
'replace the right portion over in upcharge column
opName = ":" & aCell.Value & ":"
'Correct the value in column W (Option_Name)
aCell = Replace(ActiveSheet.Range("W" & aCell.Row).Value, ":", "")
'Set corrected value (sans-colon) to opName2 and add colon to
'beginning and end of string
opName2 = ":" & aCell.Value & ":"
'Note the XID of the current row so we can ensure we look for the right upcharge
xid = ActiveSheet.Range("A" & aCell.Row).Value
Do
On Error GoTo D1
'Check the upcharges
Set uCell = uRng1.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not uCell Is Nothing Then
'Check to make sure we haven't already cycled through all
'the upcharge instances
If ActiveSheet.Range("A" & uCell.Row).Value = xid Then
'Correct the value in column CT
uCell = Replace(UCase(ActiveSheet.Range("CT" & uCell.Row).Value), UCase(opName), UCase(opName2))
End If
'Now we look in upcharge_criteria_2 column
Set uCell = uRng2.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not uCell Is Nothing Then
If ActiveSheet.Range("A" & uCell.Row).Value = xid Then
'If so then replace the string in the upcharge with the sans-colon version of the string
uCell = Replace(UCase(ActiveSheet.Range("CU" & uCell.Row).Value), UCase(opName), UCase(opName2))
End If
End If
Else
Set uCell = uRng2.Find(What:=UCase(opName), LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not uCell Is Nothing Then
'Check to make sure we haven't already cycled through all
'the upcharge instances
If ActiveSheet.Range("A" & uCell.Row).Value = xid Then
'Correct the value in column CT
uCell = Replace(UCase(ActiveSheet.Range("CU" & uCell.Row).Value), UCase(opName), UCase(opName2))
End If
Else
D1:
Exit Do
End If
End If
Loop
Else
Exit Do
End If
Loop
End If
End Sub
Я думаю, что ваше несоответствие типов связано с тем, что вы пытаетесь использовать замену (которая работает со строками) во всем диапазоне. Вместо этого вам нужно будет пройти через каждый элемент диапазона и выполнить замену. Так что-то вроде:
Dim i As Integer
i=1
While i <= endRange
Replace(ActiveSheet.Cells(i,23).Value, ":", "")
i=i+1
Wend