VBA, чтобы найти пустую строку, затем скопируйте две строки над ней, а затем перейдите к следующей пустой строке

#excel #vba #offset #blank-line

Вопрос:

Предположим, у вас есть данные Excel в формате

 Row A Row B Row C  blank row Row X Row Y Row Z blank  

Я хотел бы 1) перейти к строке с пробелом 2) скопировать все содержимое двух строк выше 3) вставить содержимое.

В приведенном выше примере результаты будут следующими

 Row A Row B Row C Row B Row C blank Row X Row Y Row Z Row Y Row Z blank  

Я в состоянии найти пробелы. Мой код в настоящее время выглядит примерно так

 Sub Find_Copy()  Dim rCell As Range Dim r As Range Dim r2 As Range  'We call the function and tell it to start the search in cell B1. Set rCell = FindNextEmpty(Range("B8")) 'this is a separate function  'Shows a message box with the cell address. Right here is where 'you write the code that uses the empty cell. rCell.Value = "Filled by macro 999" MsgBox rCell.Address amp; " " amp; rCell.Value   rCell.Offset(-2, 0).EntireRow.Select 'dmt, select the row one above the blanks  Selection.Copy  Selection.Insert Shift:=xlDown   Set rCell = Nothing  End Sub  

Кто-нибудь может помочь мне разобраться с этим? Спасибо!

Ответ №1:

Субмарина, которая выполняет эту работу, такова enhanceList . В качестве параметра он принимает диапазон, с которым вы хотите работать.

Основная идея моего макроса состоит в том, чтобы работать снизу вверх при вставке строк.

 Option Explicit  Public Sub test_enhanceList() Dim rg As Range Set rg = table1.Range("A1:A8") 'lt;lt;lt; adjust to your needs  enhanceList rg  End Sub    ' The sub which does the work Private Sub enhanceList(rgToEnhance As Range)  Dim c As Range With rgToEnhance  'we will start at the end of the range  Set c = .Cells(.Rows.Count) End With  Dim i As Long  Do  If LenB(c.Value2) = 0 Then 'test for empty cell  For i = 1 To 2  'insert empty row and take value from 3rd row above  c.EntireRow.Insert xlShiftDown  'c.offset(-1) = new cell  'c.offset(-3) = value to copy  c.Offset(-3).EntireRow.Copy c.Offset(-1)  Next  End If  Set c = c.Offset(-1) 'set c to the cell above Loop Until c.Row = rgToEnhance.Cells(1, 1).Row 'stop when first cell is reached  End Sub  

Комментарии:

1. Это намного лучше, чем то, что я делал. Если бы я мог отметить здесь ответ, он был бы таким.

2. Привет. Большое вам спасибо за вашу помощь. Однако я хотел бы скопировать всю строку целиком. Похоже, что это всего лишь копирование ячеек.

3. Я обновил код — теперь скопирована вся строка. Но я все еще смотрю только в первую ячейку строки, если она пуста.

Ответ №2:

Добавьте это после вставки, и вы сможете получить правильные строки B и C. Вам придется добавить цикл с ограничением диапазона, начинающимся до вызова функции, чтобы получить следующую пустую ячейку для добавления Y и Z и всего остального, что может последовать. Опубликуйте свой код функции, и я, вероятно, смогу написать цикл, который сделает это позже.

 rCell.Offset(-1, 0).EntireRow.Select 'dmt, select the row one above the blanks Selection.Copy  rCell.Offset(-2, 0).EntireRow.Select 'dmt, select the row one above the blanks Selection.Insert Shift:=xlDown  

Чтобы выбрать столбец, в котором вы хотите это сделать, нажав на него, измените эту строку:

 Set rCell = FindNextEmpty(ActiveCell.Offset(0, 0))  

К этому:

 Set rCell = FindNextEmpty(Selection)  

Затем перед запуском макроса выберите ячейку B1

Ответ №3:

Вместо того чтобы изменить свой ответ, я добавил новый. Добавила пару строк, чтобы найти диапазон данных, а затем прошлась по каждой ячейке в диапазоне, проверяя, пусто ли. Это устраняет необходимость в дополнительной функции.

Попробуй это:

 Sub Dan_Find_Copy()  Dim wkb As Workbook Dim rCell As Range Dim r As Range Dim r2 As Range Dim colNumber As Integer 'to store the column index Dim rowNumber As Long 'to store the last row containing data Dim i As Long 'iterator   'Need to get the range of the data Set wkb = ActiveWorkbook 'store the column number of the selection colNumber = Columns(Selection.Column).Column 'find the last row containing data rowNumber = Cells(Rows.Count, colNumber).End(xlUp).Row Set r = wkb.ActiveSheet.Range(Sheet1.Cells(1, colNumber), Sheet1.Cells(rowNumber, colNumber))  For Each rCell In r.Cells  If rCell.Value = "" Then  If MsgBox("Continue?", vbOKCancel, "Hello!") = vbOK Then   'Shows a message box with the cell address. Right here is where  'you write the code that uses the empty cell.  rCell.Value = "Filled by macro 999"  MsgBox rCell.Address amp; " " amp; rCell.Value    rCell.Offset(-2, 0).EntireRow.Select 'dmt, select the row one above the blanks  Selection.Copy  Selection.Insert Shift:=xlDown    rCell.Offset(-1, 0).EntireRow.Select 'dmt, select the row one above the blanks  Selection.Copy    rCell.Offset(-2, 0).EntireRow.Select 'dmt, select the row one above the blanks  Selection.Insert Shift:=xlDown    rCell.Select    Else   MsgBox ("You cancelled the process.")  Exit For    End If    End If   Next rCell    Set rCell = Nothing Set r = Nothing Set wkb = Nothing  End Sub  

Комментарии:

1. Привет, большое спасибо за все ваши усилия. К сожалению, я не могу успешно выполнить это. Предположим, Лист1 имеет следующие значения. B1=пустой, B2=x, B3=y, B4=z, B5=пустой, B6=x, B7=y, B8=z, B9=пустой, B10=x, B11=y, B12=z. Как бы я запустил ваш код? Еще раз спасибо.

2. Либо выберите вторую ячейку, учитывая, что первая ячейка пуста, либо проведите логический тест в начале каждого цикла и переместитесь на одну, но, честно говоря, я бы работал с предложениями Айка, а не с моими. Он короче, проще и намного чище. Вы тоже могли бы поработать в тесте для этой первой пустой ячейки.