В первые дни 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 ответа
В то время как 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.
Паскаль Кейс
Когда я впервые начал писать код, венгерские нотации были широко распространенным стандартом для 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, тебе лучше знать, что я. Я подозреваю, что изначально они сделали это для повышения производительности. По правде говоря, мне бы не хотелось быть ответственным за устранение этой неприятности и терпеть любые новые ошибки, которые появляются. Спасибо за голос ↑ ↑.
— Оловянный человек
Честно говоря, тогда чистая разница в системе управления исходным кодом не вызывала особой озабоченности 🙂
— Матье Гиндон♦
Вызов ошибки времени выполнения из общедоступной функции, вызванной из ячейки рабочего листа, заставит Excel проглотить ошибку, и ячейка будет содержать
#VALUE!
ошибка, без необходимости явно возвращатьCVErr(xlErrValue)
. Не уверен, что дублирование функции — хорошая идея, в основном — за все остальное проголосовали!— Матье Гиндон♦
@MathieuGuindon Да, но опасно, если вы вызываете UDF с помощью
Evaluate
метод из VBA (по любой причине). Всегда лучше убедиться, что в UDF не возникает ошибок. Ошибка, возникшая во времяEvaluate
вызов остановит любой код VBA на своем треке.— Кристиан Бус
… и это было бы ожидал поведение, да 🙂 наиболее вероятным исходом в противном случае будет несоответствие типов в результате захвата возвращаемого значения в
String
и получитьVariant/Error
в него — выброс из охранных оговорок укажет на настоящую причину проблемы без какого-либо косвенного указания.— Матье Гиндон♦
@MathieuGuindon Да, я не буду с этим спорить, но есть случаи, когда нужно убедиться, что
Evaluate
вызов не убивает VBA без изящной очистки. Думаю, это вопрос стиля кодирования— Кристиан Бус