openlang

Пустая ячейка равна и нулю, и пустой строке

Достался макрос, который помечает строки заказов с нулевым количеством, и он пометил заодно все пустые строки. Проверка была If ws.Cells(r, 4).Value = 0 Then. Пустая ячейка отдаёт Variant со значением Empty, а Empty равно 0 (и "" тоже, если написать проверку наоборот, так что и этим путём не выиграть). Никто, разумеется, ничего не объявлял, так что весь макрос работал на Variant, и сравнение сделало ровно то, что делают Variant.

Быстрое решение - IsEmpty перед сравнением. Ладно. Но это заставило посчитать, сколькими способами значение в VBA может означать «здесь ничего нет». Empty из пустой ячейки, Null из поля Access, Nothing у объектной переменной, "", 0 и значение ошибки, если в ячейке видно #N/A. Шесть вариантов записи, и для каждого своя проверка.

Как вы моделируете «нет значения» в VBA? Переводите на входе в типизированные переменные с флагом или оставляете Variant и везде проверяете через VarType?

Разговор продолжается 7

Следуя доводам
  1. Ссылка на ответ

    Прочитайте ячейку один раз и решите, что это, в одном месте. Дальше остальная часть макроса получает типизированное значение и больше не видит Variant.

    Dim v As Variant
    v = ws.Cells(r, 4).Value2
    
    Select Case VarType(v)
        Case vbEmpty
            hasQty = False
        Case vbDouble
            hasQty = True
            qty = CDbl(v)
        Case vbString
            hasQty = False
            LogOddCell ws, r, v
        Case Else
            hasQty = False
            LogOddCell ws, r, v
    End Select

    Здесь важен Value2. Через Value ячейка с денежным форматом или датой приходит как vbCurrency или vbDate и проваливается в Case Else. Ячейка с ошибкой даёт vbError и тоже попадает в Case Else, так что её запишут в лог, а не посчитают. LogOddCell здесь означает то, что у вас уже делается с пропущенными строками.

  2. Ссылка на ответ

    У человека, который заполняет этот лист, способов сделать «ничего» больше, чем в списке. Нажал Delete, получился Empty. Ткнул пробел, чтобы очистить, и получилась строка из одного символа, которая на экране выглядит пустой. Набрал '0, потому что ноль в каком-то формате всё время пропадал, и теперь это текст "0", который ветка vbDouble пропускает. При прокрутке все три выглядят одинаково. Есть ли дешёвый способ показать пользователю, какие ячейки макрос пропустил, заливкой или чем-то таким, чтобы ячейки с пробелом исправляли там, где их вводят?

  3. Ссылка на ответ

    Стало интересно, есть ли у Empty собственный тип или он его одалживает, и окно Immediate отвечает, что одалживает тот, который нужен окружающему выражению. Empty + 1 равно 1, Empty & "x" даёт "x", а Empty = 0 и Empty = "" оба True. Так что это не значение, равное нулю. Это значение, которое становится нулём или пустой строкой в зависимости от того, кто спрашивает, и поэтому проверка = 0 так долго казалась рабочей. Интересно, какая проверка замечает разницу, и, насколько видно, это только IsEmpty и VarType.

  4. Ссылка на ответ

    Перед этим стоит добавить ещё один этап. Сначала прочитать весь столбец в массив, классифицировать каждую ячейку и только потом считать, чтобы итоги никогда не начинались с частично проверенного диапазона. data = rng.Value2 даёт двумерный массив, по элементу на ячейку, и это заметно быстрее, чем вызов Cells на каждую строку.

    Тут есть подвох. Если диапазон состоит из одной ячейки, Value2 возвращает само значение, а не массив, и data(1, 1) падает. Поэтому сразу после чтения проверьте IsArray(data) и сами оберните одиночное значение перед классификацией. Тогда число пустых, числовых и странных ячеек известно до того, как что-то начнут складывать.

  5. Ссылка на ответ

    Сначала посчитайте, потом чините. На таком листе нужны три числа. Ячейки, где IsEmpty истинно, ячейки, где нет, но значение "", и всё остальное. Про среднюю группу обычно забывают. Формула вроде =IF(B2="","",B2*C2) ничего не показывает, IsEmpty даёт False, потому что в ячейке формула, а VarType даёт vbString. COUNTBLANK в Excel считает такие ячейки пустыми, так что проверка по листу и проверка в макросе могут разойтись ровно на эту группу.

  6. Ссылка на ответ

    Ваши три подсчёта до всяких правок всё перевернули. Из строк, которые пометил макрос, по-настоящему пустых оказалось всего несколько. Остальное было пустотами от формул во вспомогательном столбце, который кто-то добавил (с заголовком просто «x», спасибо, кто бы вы ни были). Так что исправление с IsEmpty не поймало бы почти ничего, а дело сочли бы законченным.

    В итоге взят Select Case по Value2 от smallprint плюс ветка Case vbString, где "" значит «нет количества», а всё остальное идёт в лог. На листе лога сейчас одиннадцать записей, и все они того самого пробельного вида, о котором писал kim_dh.

Другие стороны того же вопроса

  1. Единицы измерения как дешёвые идентификаторы

    Для целочисленных идентификаторов я пробую единицы измерения вместо объединений с одним случаем, и хочется услышать второе мн…

    Ответы 1fsharp
  2. Хелпер, перенесённый из Java, в Groovy вызывает другую перегрузку

    Java-класс хелпера переехал в Groovy на стороне сборочного скрипта, и тот же вызов ушёл в другой метод. По порядку. В Java об…

    Ответы 3groovyjava
  3. Проверка JSON до размеченного объединения

    Утверждение типа только говорит компилятору, во что верить. Внешний ответ приходит байтами, и пока его никто не проверил, нич…

    Ответы 9typescript