Как удалить строки нулевой длины в Excel, используя VBA? - PullRequest
3 голосов
/ 07 мая 2019

Я создал инструмент в VBA для Excel, который анализирует файлы .xlsx, которые мы получаем на основе ряда критериев. Одним из них является количество пустых ячеек в наборе данных. Однако, к сожалению, я заметил, что ряд файлов, которые мы получаем, содержат ячейки со строками нулевой длины, которые «неправильно» считаются непустыми ячейками.

На самом деле очень полезно для всего процесса, если я могу просто удалить их из файла.

Я много гуглял эту проблему, но единственное решение, которое мне удалось найти, - это пройтись по всем ячейкам на листе (я также пробовал только константы, а также использовать Find, чтобы найти все zls) , Это не очень эффективно, поскольку рабочие листы содержат большое количество данных. РЕДАКТИРОВАТЬ: я также попробовал метод UsedRange.values ​​= UsedRange.values, но это удаляет начальные нули, которые мне требуются.

Я также обнаружил, что это работает (- @ - это случайная строка, которая вряд ли будет единственной ячейкой в ​​моих данных, и, если она есть, ее можно удалить):

ws.UsedRange.Replace what:=vbNullString, replacement:="-@-", _
                            lookat:=xlWhole, MatchCase:=False
ws.UsedRange.Replace what:="-@-", replacement:="", _
                            lookat:=xlWhole, MatchCase:=False

но если я делаю это только с помощью одной замены, это не так:

ws.UsedRange.Replace what:=vbNullString, replacement:="", _
                            lookat:=xlWhole, MatchCase:=False

С первым все в порядке, но есть ряд проблем:

  1. Это занимает вдвое больше времени, чем одна замена
  2. Не всегда ясно, произошел сбой или он продолжил работать
  3. Если произойдет сбой, у меня останется несколько ячеек, содержащих - @ -, что не всегда очевидно, и инструмент должен быть в порядке, чтобы его мог использовать тот, кто не понимает VBA.

Итак, мои вопросы:

  1. Есть ли способ сделать это, используя только одну замену? Почему замена работает с двойной заменой, а не с одиночной?
  2. Если первое невозможно, то есть ли способ «откатить» замену в случае сбоя кода?
  3. Есть ли способ обновления строки состояния, чтобы показать, как далеко проходит замена, чтобы доказать, что код выполняется (так же, как при запуске замены в самом Excel)?
  4. Или есть просто лучший способ сделать все это?

Заранее спасибо!

РЕДАКТИРОВАТЬ: К сожалению, из-за обрабатываемых данных мне нужно сохранить форматирование, включая ведущие нули

РЕДАКТИРОВАТЬ: Вот пример данных, которые я смотрю. Я хочу заменить строки нулевой длины (которые являются непустыми ячейками, в которых нет значения), чтобы они были действительно пустыми ячейками.

Table containing zero-length-strings

Ответы [ 3 ]

0 голосов
/ 07 мая 2019

Я знаю, что это тоже цикл, но, возможно, более быстрый путь:

До:

enter image description here

Запустите этот код на примере данных:

Dim X As Double

Option Explicit

Sub Test()

Application.ScreenUpdating = False
Application.Calculation = xlManual

With ActiveWorkbook.Sheets(1).Range("A1:C7")
    For X = 1 To 3
        .AutoFilter Field:=X, Criteria1:=""
        .Columns(X).Offset(1, 0).SpecialCells(xlCellTypeVisible).Clear
    Next X
    .AutoFilter
End With

Application.Calculation = xlAutomatic
Application.ScreenUpdating = True

End Sub

После:

enter image description here

0 голосов
/ 08 мая 2019

Чтение листа в набор записей ADO, а затем копирование набора записей на новый лист, кажется, решает эту проблему.Попробуйте этот код VBA:

Sub copy_data()

Dim cn As Object
Set cn = CreateObject("ADODB.Connection")

With cn
    .Provider = "Microsoft.ACE.OLEDB.12.0"
    .ConnectionString = "Data Source=" & ThisWorkbook.FullName & ";" & _
        "Extended Properties=""Excel 12.0 Macro;IMEX=1;HDR=YES"";"
    .Open
End With

Dim rs As Object
Set rs = CreateObject("ADODB.Recordset")

rs.Open "SELECT * FROM [Sheet1$];", cn

Dim i As Integer
Dim fld As Object

With ThisWorkbook.Worksheets("Sheet2")
    .UsedRange.ClearContents

    i = 0
    For Each fld In rs.Fields
        i = i + 1
        .Cells(1, i).Value = fld.Name
    Next fld

    .Cells(2, 1).CopyFromRecordset rs
    .UsedRange.Columns.AutoFit
End With

rs.Close
cn.Close

End Sub

Примечания:

  • измените имена листов в коде, чтобы они соответствовали именам листов, которые вы используете.Вы должны поставить знак $ после имени листа, которое вы используете в rs.Open.Если бы ваш лист назывался «Данные», то вы бы поместили rs.Open "SELECT * FROM [Data$];", cn
  • в расширенные свойства строки подключения, HDR=YES использовался, чтобы указать, что данные имеют заголовки.ADO может изменить некоторые имена столбцов, если они содержат определенные символы - в основном символ ., который обычно заменяется символом #

Потенциальные проблемы:

  • ваши данные должны быть примерно в формате таблицы - т.е. имена столбцов в строке 1 со значениями данных под каждым именем столбца
  • любые формулы в данных будут преобразованы в значения
  • форматирование ячеекне будут скопированы, но числа, отформатированные как текст, останутся в виде текста, поэтому начальные нули будут сохранены
  • любой текст значения ячейки, длина которого превышает 255 символов, вероятно, будет обрезан до 255 символов (можно обойтипри необходимости)

В зависимости от ваших данных, использование ADO может создать больше проблем, чем решить

0 голосов
/ 07 мая 2019

У вас могут быть ячейки с формулами, которые возвращают пустую строку, или ячейки с пустыми строковыми константами.Чтобы очистить ячейки второго типа:

Sub KillNullConstants()
    Dim cell As Range, Konstants As Range, rng As Range
    Set Konstants = ActiveSheet.UsedRange.Cells.SpecialCells(xlCellTypeConstants)
    Set rng = Nothing
    For Each cell In Konstants
        If Len(cell) = 0 Then
            If rng Is Nothing Then
                Set rng = cell
            Else
                Set rng = Union(rng, cell)
            End If
        End If
    Next cell

    If Not rng Is Nothing Then
        rng.ClearContents
    End If
End Sub

Чтобы очистить ячейки формулы, которые возвращают нулевые строки, просто измените строку кода SpecialCells.

...