VB6 Может ли IsNumeric ошибаться?

Можно ли проверить строку с помощью IsNumeric() и чтобы она возвращала true, но когда вы приводите ту же строку к целому числу с помощью CInt() и присваиваете ее переменной типа integer, это выдает ошибку несоответствия типа?

Я спрашиваю, потому что я получал ошибку несоответствия типов, поэтому я использовал IsNumeric(), чтобы проверить, является ли строка числовой, прежде чем пытаться ее привести, но я все равно получаю ошибку.

Я рву на себе волосы с этим.

Вот код, о котором идет речь. iGlobalMaxAlternatives = CInt(strMaxAlternatives) - это место, где возникает ошибка.

Dim strMaxAlternatives As String
Dim iGlobalMaxAlternatives As Integer
iGlobalMaxAlternatives = 0
bSurchargeIncInFare = True

strMaxAlternatives = ReadStringKeyFromRegistry("Software\TL\Connection Strings\" & sConn & "\HH", "MaxAlt")

If IsNumeric(strMaxAlternatives) And strMaxAlternatives <> "" Then
    iGlobalMaxAlternatives = CInt(strMaxAlternatives)
End If

person Community    schedule 22.01.2009    source источник
comment
Показать код? Перехватить ошибку и вывести исходную строку?   -  person Joel Coehoorn    schedule 22.01.2009
comment
Я согласен, если вы покажете код, мы сможем помочь.   -  person RS Conley    schedule 22.01.2009
comment
Не имеет прямого отношения к этому вопросу, но я обнаружил, что IsNumeric терпит неудачу, если у вас есть, например. номер формата США с '.' десятичный разделитель, но если вы работаете на машине с европейскими региональными настройками, в которых используется десятичный разделитель ',', то IsNumeric завершится ошибкой.   -  person Chris    schedule 20.10.2010


Ответы (10)


У вас может быть переполнение из-за максимального целочисленного размера; тип валюты на самом деле очень хорошо подходит для больших чисел (но остерегайтесь любых региональных проблем). См. изменения ниже для обсуждения Int64.

Согласно документации MSDN на IsNumeric:

  • IsNumeric возвращает значение True, если тип данных Expression — Boolean, Byte, Decimal, Double, Integer, Long, SByte, Short, Single, UInteger, ULong или UShort, или объект, который содержит один из этих числовых типов. Он также возвращает True, если Expression является символом или строкой, которую можно успешно преобразовать в число.

  • IsNumeric возвращает False, если Expression имеет тип данных Date или тип данных Object и не содержит числового типа. IsNumeric возвращает False, если Expression является символом или строкой, которую нельзя преобразовать в число.

Поскольку вы получаете несоответствие типов, возможно, преобразованию мешает Double. IsNumeric не гарантирует, что это целое число, просто оно соответствует одной из числовых возможностей. Если число двойное, возможно, региональные настройки (запятая или точка и т. д.) вызывают исключение.

Вы можете попробовать преобразовать его в двойное, а затем в целое число.

' Using a couple of steps
Dim iValue As Integer
Dim dValue As Double
dValue = CDbl(SourceValue)
iValue = CInt(iValue)
' Or in one step (might make debugging harder)
iValue = CInt(CDbl(SourceValue))

РЕДАКТИРОВАТЬ: после вашего разъяснения кажется, что вы получаете преобразование переполнения. Сначала попробуйте использовать Long и CLng() вместо CInt(). Тем не менее, есть вероятность, что запись является Int64, что сложнее при использовании VB6.

Я использовал следующий код для типов LARGE_INTEGER и Integer8 (оба Int64), но он может не работать в вашей ситуации:

testValue = CCur((inputValue.HighPart * 2 ^ 32) + _
                  inputValue.LowPart) / CCur(-864000000000)

Этот пример был взят из примера истечения срока действия пароля LDAP, но, как я уже сказал, он может работать или не работать в ваш сценарий. Если у вас нет типа LARGE_INTEGER, это выглядит так:

Private Type LARGE_INTEGER
    LowPart As Long
    HighPart As Long
End Type

Найдите LARGE_INTEGER и VB6 для получения дополнительной информации.

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

If IsNumeric(strMaxAlternatives) And strMaxAlternatives <> "" Then
    On Error Resume Next
    iGlobalMaxAlternatives = CInt(strMaxAlternatives)
    If Err.Number <> 0 Then
        Debug.Print "Conversion Error: " & strMaxAlternatives & _
                    " - " & Err.Description
    EndIf
    On Error Goto YourPreviousErrorHandler
End If
person Ryan    schedule 22.01.2009

Да, "3,41" будет числом, но не целым числом.

person workmad3    schedule 22.01.2009
comment
Правильный CInt(3.41) сам по себе не вызывает ошибки несоответствия типов в VB6 при назначении целому числу -1. - person RS Conley; 22.01.2009

VB6 не предоставляет хороших методов, гарантирующих, что CInt не выйдет из строя. Я нашел самый простой способ - просто использовать обработку ошибок.

function TryParse(byval text as string, byref value as integer) as boolean
  on error resume next
  value = CInt(text)
  TryParse = (err.number = 0)
endfunction

Конечно, ваши предпочтения по обработке ошибок могут различаться.

person Craig Gidney    schedule 22.01.2009

Да. Попробуй это:

If IsNumeric("65537") Then
    Dim i As Integer
    i = CInt("65537") 'throws an error on this line!
End If

Это переполнение, но я думаю, что оно иллюстрирует ненадежность IsNumeric() в целом (особенно для целых чисел — для удвоений это намного надежнее).

person Ant    schedule 22.01.2009

Согласно документации VB6, «IsNumeric возвращает True, если тип данных Expression — Boolean, Byte, Decimal, Double, Integer, Long, SByte, Short, Single, UInteger, ULong или UShort, или объект, который содержит один из этих числовые типы. Он также возвращает True, если Expression является Char или String, который может быть успешно преобразован в число».

Многие из них не могут быть преобразованы в целое число. Например, "1,5" является числовым, но не целым числом. Таким образом, вы можете преобразовать его в число, но не обязательно в целое число.

person Bryan Oakley    schedule 22.01.2009
comment
CInt() выполняет преобразование, а не приведение. - person Joel Coehoorn; 22.01.2009
comment
Спасибо что подметил это. Я изменил слово «приведение» на «преобразование». - person Bryan Oakley; 22.01.2009

Следующий код работает без ошибки несоответствия типов в Visual BASIC 6.

Dim I As Integer
I = CInt("3.41")

То же самое для этого варианта

Dim I As Integer
Dim TempS As String
TempS = "3.41"
I = CInt(TempS)

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

CInt и Int преобразуются в число, но по-разному обрабатывают округление. Прямое назначение работает и эквивалентно использованию CInt. Тем не менее, я рекомендую продолжать использовать CInt, чтобы сделать операцию понятной вам и вашим коллегам-разработчикам в будущем.

CInt работает с числами с такими запятыми, как "3041,41". Однако в VB6 есть проблемы с обработкой настроек региона, поэтому, если вы используете нотацию, отличную от стандартного американского английского, вы получите странные результаты и ошибки.

person RS Conley    schedule 22.01.2009

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

person NotMe    schedule 22.01.2009

IsNumeric вернет true, если сможет преобразовать строку в число. Даже если в строке есть нечисловые символы. Я всегда перебираю строку по одному символу за раз и проверяю каждый символ. Если один символ не работает, я могу вернуть ошибку.

person jac    schedule 22.01.2009

Только что нашел этот самородок. Если вы запустите следующее, сценарий № 1 вернет TRUE, но сценарии № 2 и № 3 завершатся ошибкой:

SELECT ISNUMERIC('98,0') AS isNum   -- Fails

SELECT CONVERT(INT, '98,0')   -- Fails

SELECT CONVERT(NUMERIC(11,4), '98,0')     -- Fails
person Russ    schedule 29.01.2010

Два варианта...

Сдача

If IsNumeric(strMaxAlternatives) And strMaxAlternatives <> "" Then
    iGlobalMaxAlternatives = CInt(strMaxAlternatives)
End If

To

If IsNumeric(strMaxAlternatives) And strMaxAlternatives <> "" Then
    iGlobalMaxAlternatives = CDbl(strMaxAlternatives) ' Cast to double instead'
End If

Or

If IsNumeric(strMaxAlternatives) And strMaxAlternatives <> "" Then
    If CDbl(strMaxAlternatives) Mod 1 = 0 Then ' Make sure there\'s no decimal points'
        iGlobalMaxAlternatives = CInt(strMaxAlternatives)
    End If
End If
person Andrew G. Johnson    schedule 22.01.2009