Функция midStr () кода Excel VBA с использованием левой и правой позиции вместо длины, используемой с mid ()

В первые дни Basic (1970-е, когда я начал кодировать) функция midStr () напрямую использовала левую и правую позиции, а не left и length, которые мы теперь используем с mid (). Я всегда считал более эффективным кодирование с использованием старого метода midStr (), поэтому я, наконец, просто создал код для этого. Это, конечно, не так эффективно, как mid (), и если я имею дело с большим количеством данных, я бы использовал mid () напрямую вместо этого, но для простоты мне больше нравится старый способ, проще просто кодировать rightPos, а не rightpos — leftPos + 1 и для проверки на нуль.

Я также сделал rightPos необязательным, и когда он не используется, вместо него используется длина textin, поэтому он просто вернет остаток текста, начиная с leftPos.

Любая критика приветствуется, спасибо.

Function midStr(ByVal textin As String, _
                ByVal leftPos As Long, _
       Optional ByVal rightPos As Variant) As Variant
   'midStr returns textin string using leftPos and rightPos (rather than num_chars).
   'rightPos is optional, len(textin) is used for the rightPos when it's not otherwise defined.
  
   On Error GoTo midStrErr
   If IsMissing(rightPos) Then rightPos = Len(textin)
   If rightPos < leftPos Then
      midStr = vbNullString
   Else
      midStr = Mid(textin, leftPos, rightPos - leftPos + 1)
   End If
   Exit Function
 
midStrErr:
   On Error Resume Next
   midStr = CVErr(xlErrValue) '#VALUE!
End Function

2 ответа
2

В то время как Optional ByVal rightPos As Variant это отличная идея, потому что вы можете использовать IsMissing функция, она вносит ненужные ошибки. Например, Debug.Print midStr("Hello World", 1, Nothing) напечатает «Ошибка 2015» в окне «Немедленное». Эта строка не должна компилироваться.

Я бы объявил rightPos параметр как Long. Компилятор позаботится о некоторых проблемах — например, вы не сможете передать объект. В Long по умолчанию будет 0, поэтому вы можете заменить If IsMissing(rightPos) Then rightPos = Len(textin) с If rightPos = 0 Then rightPos = Len(textin).

Общепринятое соглашение в VBA заключается в том, что имена методов пишутся с PascalCase и имена переменных пишутся с camelCase. Более того, функция, определяемая пользователем (UDF) Excel, обычно пишется с ЗАПИСНЫМИ буквами.

Эта функция, похоже, разработана как Excel UDF. Что, если вам нужно использовать его в VBA? Ошибки Excel ничего не значат для другого метода VBA. Я бы написал это как отдельную функцию только для VBA, которая будет работать на любом хосте приложения с поддержкой VBA (нет необходимости возвращать вариант):

Public Function MidStr(ByVal textin As String, _
                       ByVal leftPos As Long, _
              Optional ByVal rightPos As Long _
) As String
    Const methodName As String = "MidStr"
    
    If leftPos < 0 Then Err.Raise 5, methodName, "Invalid left position"
    If rightPos < 0 Then Err.Raise 5, methodName, "Invalid right position"
    
    If rightPos = 0 Then rightPos = Len(textin)
    If rightPos < leftPos Then
        MidStr = vbNullString
    Else
        MidStr = VBA.Mid$(textin, leftPos, rightPos - leftPos + 1)
    End If
End Function

Тогда у меня был бы UDF Excel:

Public Function MID_STR(ByVal textin As String, _
                        ByVal leftPos As Long, _
               Optional ByVal rightPos As Long _
) As Variant
    On Error GoTo ErrorHandler
    MID_STR = MidStr(textin, leftPos, rightPos)
Exit Function
ErrorHandler:
    MID_STR = CVErr(xlErrValue)
End Function

Это позволяет использовать MidStr функции в других методах VBA и MID_STR будет вызываться только через интерфейс Excel.

  • Вызов ошибки времени выполнения из общедоступной функции, вызванной из ячейки рабочего листа, заставит Excel проглотить ошибку, и ячейка будет содержать #VALUE! ошибка, без необходимости явно возвращать CVErr(xlErrValue). Не уверен, что дублирование функции — хорошая идея, в основном — за все остальное проголосовали!

    — Матье Гиндон


  • 1

    @MathieuGuindon Да, но опасно, если вы вызываете UDF с помощью Evaluate метод из VBA (по любой причине). Всегда лучше убедиться, что в UDF не возникает ошибок. Ошибка, возникшая во время Evaluate вызов остановит любой код VBA на своем треке.

    — Кристиан Бус


  • … и это было бы ожидал поведение, да 🙂 наиболее вероятным исходом в противном случае будет несоответствие типов в результате захвата возвращаемого значения в String и получить Variant/Error в него — выброс из охранных оговорок укажет на настоящую причину проблемы без какого-либо косвенного указания.

    — Матье Гиндон


  • 1

    @MathieuGuindon Да, я не буду с этим спорить, но есть случаи, когда нужно убедиться, что Evaluate вызов не убивает VBA без изящной очистки. Думаю, это вопрос стиля кодирования

    — Кристиан Бус

Паскаль Кейс

Когда я впервые начал писать код, венгерские нотации были широко распространенным стандартом для VBA. Спустя годы компания Camel Case взяла верх. На мой взгляд, настало время, чтобы Pascal Case стал стандартом.

Это было моей тирадой в течение некоторого времени. Я приветствую дебаты всех пользователей, от новичков до MVP. Следующий фрагмент иллюстрирует мой аргумент:

Dim value As Range
value = Range("A1").value

Dim text As String
text = Range("A1").text

Использование Camel Casing для имени переменной изменяет регистр для всех свойств и методов, которые имеют общее имя для всего проекта. Я ответил на более чем 2000 вопросов на форуме за эти годы. Не могу сказать, сколько раз меня отбрасывала неподходящая оболочка. Смешно, что Microsoft так и не исправила это.

Подпись функции

Function midStr(ByVal textin As String, _
                ByVal leftPos As Long, _
       Optional ByVal rightPos As Variant) As Variant

Как упомянул Кристиан Бузе, rightPos следует набирать как Long, а сама функция должна возвращать строку. Я бы добавил, что rightPos довольно сбивает с толку.

* используются левая и правая позиции напрямую, а не левая и длина

Когда я впервые прочитал это, я подумал: «midStr возвращает строку, используя функции Left () и Right (). Как странно. Интересно, насколько это проще, чем mid» НЕПРАВИЛЬНЫЙ!! Оказывается, он использует начальную и конечную позиции для возврата подстроки. Это здорово, мне это нравится!

Я бы порекомендовал вызвать функцию SubString но он назван в честь старинной функции VB. Для меня было бы лучше, если бы он возвращал на 1 символ меньше, как большинство подобных функций подстроки.

leftPos и rightPos с другой стороны, они должны уйти. Это слишком сбивает с толку, особенно потому, что функция уже ведет себя немного иначе, чем ожидалось, возвращая дополнительный символ. я хотел бы использовать start и end если бы они не были зарезервированными словами. StartIndex и EndIndex или же pStart и pEnd для меня гораздо более интуитивно понятны.

Функция MidStr (ByVal Text As String, ByVal StartIndex As Long, необязательный ByVal EndIndex как вариант) As String ‘midStr возвращает текстовую строку, используя startIndex и endIndex (а не num_chars). ‘endIndex является необязательным, len (текст) используется для endIndex, если он не определен иначе.

   On Error GoTo midStrErr
   If EndIndex = 0 Then EndIndex = Len(Text)
   If EndIndex < StartIndex Then
      MidStr = vbNullString
   Else
      MidStr = Mid(Text, StartIndex, EndIndex - StartIndex + 1)
   End If
   Exit Function
 
midStrErr:
   On Error Resume Next
   MidStr = CVErr(xlErrValue) '#VALUE!
End Function

  • Я недавно усыновил PascalCaseEverywhere и не оглядывался с тех пор (принял camelCaseForLocals за годы влияния C # на мой стиль VB!). Что касается исправления MS, я могу ошибаться, но я понимаю, что это невозможно без переписывания того, как VBA кэширует имена в области видимости … чтобы сделать их чувствительными к регистру.

    — Матье Гиндон

  • @MathieuGuindon, тебе лучше знать, что я. Я подозреваю, что изначально они сделали это для повышения производительности. По правде говоря, мне бы не хотелось быть ответственным за устранение этой неприятности и терпеть любые новые ошибки, которые появляются. Спасибо за голос ↑ ↑.

    — Оловянный человек

  • Честно говоря, тогда чистая разница в системе управления исходным кодом не вызывала особой озабоченности 🙂

    — Матье Гиндон

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *