🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA IsNumeric in Excel — Why It Says Yes to Things That Are Not Numbers

|

VBA IsNumeric in Excel — Why It Says Yes to Things That Are Not Numbers

TL;DRIsNumeric(value) returns True when VBA thinks it could convert the value to a number — which is a much wider net than the clean integers you probably have in mind. It says True to "1E5" (scientific notation), "&HFF" (a hex literal), "1,000" (a thousands separator), " 42 " (padded with spaces) and even "12-" (a trailing sign). It is also locale-dependent, so "1,5" is a number on a German machine and not on an American one. Use it as a cheap first gate, but the moment you need exactly a clean integer or a digits-only code, pin the shape with the Like operator instead.

Sub IsNumericSurprises()
    Debug.Print IsNumeric("123")      ' True  - as expected
    Debug.Print IsNumeric("1E5")      ' True  - reads as 100000 (scientific)
    Debug.Print IsNumeric("&HFF")     ' True  - reads as 255 (hex literal)
    Debug.Print IsNumeric("1,000")    ' True  - thousands separator
    Debug.Print IsNumeric("  42  ")   ' True  - leading/trailing spaces ignored
    Debug.Print IsNumeric("12-")      ' True  - trailing sign is allowed

    Debug.Print IsNumeric("12.3.4")   ' False - two decimal points
    Debug.Print IsNumeric("")         ' False - empty string
    Debug.Print IsNumeric("2026-01-01") ' False - that is a date, use IsDate
End Sub

What you'll learn

  • The mental model — IsNumeric tests what VBA could parse, not what you meant
  • The three text testers of rising power, and which question each one answers
  • Why scientific notation and hex literals sail straight through
  • Why spaces, signs, and thousands separators all pass
  • Why IsNumeric is locale-dependent, and how that corrupts data across machines
  • IsNumeric vs IsNumber vs IsDate, and the strict check to use instead

The mental model: IsNumeric asks what VBA could parse, not what you meant

IsNumeric is not a validator. It is a preview of VBA's own type coercion: it returns True for any string that CDbl (or the implicit conversion behind Val-style parsing) would swallow without an error. That is a deliberately generous rule, because VBA's numeric parser understands scientific notation, hexadecimal and octal literals, currency and grouping symbols, and surrounding whitespace.

So the right question in your head is never "is this a number?" It is "would VBA convert this to a number if I asked it to?" — and the answer is yes far more often than you want. Every surprise below follows directly from that one framing.

The three testers, of rising power

IsNumeric is the first rung of a ladder. Before you trust any string, you test it — and VBA hands you three testers, each answering a different question and each lying to you in its own way:

Tester The question it answers Its signature lie
IsNumeric Could VBA parse this as a number? Says yes to "1E5", "&HFF", "12-"
Like Does the whole string fit this shape? Case depends on a module-wide switch
RegExp Does it match a real pattern, and what is inside? Returns nothing until you set Global and reach SubMatches

Reach for the weak one and bad data slips through; reach for the heavy one and you drown in setup. The skill is knowing which question you are actually asking. IsNumeric answers the loosest question, which makes it the fastest to reach for and the easiest to get wrong. When "could be a number" is not tight enough — you need exactly three digits, or a positive amount, or a code with no letters — you have climbed off the bottom rung and want Like or a real pattern.

Trap 1: scientific notation and hex literals sail straight through

The two that catch everyone: "1E5" and "&HFF".

Debug.Print IsNumeric("1E5")    ' True
Debug.Print CDbl("1E5")         ' 100000     <- E is an exponent
Debug.Print IsNumeric("&HFF")   ' True
Debug.Print CLng("&HFF")        ' 255        <- &H is a hex literal

This is not a bug — it is VBA being consistent. But it is a data disaster when the field is a code rather than a quantity. A product ID like 1E5, an account suffix like 12E3, or a part number that happens to start &H all pass validation and then get silently turned into a large integer the moment you convert. The user typed a label; your macro stored a number in the millions and moved on without a word.

If the column is meant to hold identifiers, IsNumeric is the wrong gate entirely — you do not want "parseable as a number", you want "these exact characters". That is a job for the Like operator or a straight string comparison, not IsNumeric.

Trap 2: spaces, signs, and thousands separators all pass

VBA's parser is forgiving about the cosmetics around a number, so all of these return True:

Debug.Print IsNumeric("  42  ")  ' True - surrounding whitespace is trimmed
Debug.Print IsNumeric("+5")      ' True - leading sign
Debug.Print IsNumeric("12-")     ' True - TRAILING sign (the famous one)
Debug.Print IsNumeric("1,000")   ' True - thousands separator
Debug.Print IsNumeric("(5)")     ' True - accounting-style negative

The trailing-sign case ("12-") surprises almost everyone, and the accounting parentheses ("(5)") are a genuine footgun when you import a finance export and half your negatives arrive wrapped in brackets. Meanwhile the things you might expect to pass do not: an internal space ("1 2"), a fraction ("1/2"), and an empty string all return False. The rule is not "looks like digits" — it is "matches one of VBA's accepted numeric shapes", and that set is both wider and stranger than intuition.

Trap 3: it is locale-dependent, so it corrupts data across machines

This is the quiet one that survives testing and fails in production. IsNumeric respects the machine's regional settings for the decimal and grouping separators:

' On a US machine (decimal = ".")
Debug.Print IsNumeric("1,5")   ' False - comma is not a decimal point here
Debug.Print IsNumeric("1.5")   ' True

' On a German machine (decimal = ",")
Debug.Print IsNumeric("1,5")   ' True  - comma IS the decimal point
Debug.Print IsNumeric("1.5")   ' True  - dot read as a grouping separator

The same workbook, the same macro, two different answers depending on who opens it. A validation step that passes on your desk lets a colleague's "1,5" through as 1.5 — or rejects it outright — and you will never see it in a test. When the value comes from a file, a web page, or another region, do the parsing yourself with an explicit assumption (CDbl respects locale; Val always treats . as the decimal), rather than trusting IsNumeric to mean the same thing everywhere.

IsNumeric vs IsNumber vs IsDate

Three functions people reach for interchangeably, three different jobs:

  • IsNumeric(x) — a VBA function that asks whether a string could be parsed as a number. This is the one this article is about.
  • Application.WorksheetFunction.IsNumber(cell) — the worksheet ISNUMBER, which asks whether a cell's stored value is already of numeric type. It does not parse text; IsNumber("123") on a text-formatted cell is False even though IsNumeric("123") is True.
  • IsDate(x) — the sibling gate for dates. IsNumeric("2026-01-01") is False; use IsDate for anything that should be a date, and note it is every bit as locale-dependent as IsNumeric.

Use IsNumber when you are asking about a value that is already in a cell; use IsNumeric when you are sanitising text before you convert it.

The opinion: IsNumeric is a cheap gate, not a validator

IsNumeric earns its place as a fast rejection of obvious garbage — a blank cell, a name, a stray symbol. Let it throw those out cheaply. But the day your rule is tighter than "could be a number" — a five-digit ZIP, a positive quantity, an order code with no letters — IsNumeric stops being an asset and becomes a false sense of safety, because it green-lights scientific notation, hex, padded strings and locale-specific separators you never meant to accept.

The fix is to say the shape out loud. For "exactly three digits", s Like "###". For "digits only, any length", Len(s) > 0 And Not (s Like "*[!0-9]*"). For anything with structure — a group to extract, a pattern that repeats — you have climbed to the top of the ladder and want a real pattern. And whatever you decide passes, convert it immediately under the same locale assumption you tested with, so "valid" and "converted" can never disagree.

When validation is the whole job — describe it instead

Half the time the real task is not "is this numeric" but "clean this column: strip the codes that look like numbers, flag the ones with the wrong number of digits, coerce the rest, and tell me which rows you touched." By the time you have chained IsNumeric, a Like shape check, a locale-aware conversion and a log of the exceptions, the plumbing dwarfs the answer. ExcelMaster lets you state that goal in plain English — "validate column C as positive whole quantities, list every row that fails and why" — and it generates Python that reads the data, applies the real rule, backs up your file first, and hands back the exceptions. You describe the check; it handles the scientific notation, the padding, and the locale.

Frequently asked questions

What does IsNumeric do in VBA?

IsNumeric(expression) returns a Boolean: True if VBA could convert the expression to a number, and False otherwise. It is generous — it accepts scientific notation, hexadecimal (&H) and octal (&O) literals, thousands separators, surrounding whitespace and leading or trailing signs — so it means "parseable as a number", not "a clean integer".

Why does IsNumeric return True for a value that is not a number?

Because the value is one VBA's parser recognises. "1E5" is scientific notation, "&HFF" is a hex literal, "1,000" uses a thousands separator, and "12-" has a trailing sign — all valid numeric shapes to VBA. If you need a stricter definition, test the shape with Like (for example s Like "###" for exactly three digits) instead of IsNumeric.

How do I check that a string is only digits in VBA?

Use a Like pattern rather than IsNumeric. Len(s) > 0 And Not (s Like "*[!0-9]*") is True only when s is non-empty and contains no non-digit character — a genuine digits-only test that, unlike IsNumeric, rejects "1E5", "1,000" and "12-".

What is the difference between IsNumeric and IsNumber in VBA?

IsNumeric is a VBA function that tests whether a string could be parsed as a number. WorksheetFunction.IsNumber (the worksheet ISNUMBER) tests whether a cell's value is already stored as a numeric type. A text cell containing 123 gives IsNumeric = True but IsNumber = False.

Is IsNumeric affected by regional settings?

Yes. IsNumeric uses the machine's decimal and grouping separators, so "1,5" is numeric on a machine where the comma is the decimal point and not on one where the dot is. For portable results, convert with an explicit rule (Val always uses . as the decimal; CDbl respects the current locale) instead of relying on IsNumeric to behave identically everywhere.

Tested in

Tested in: Excel 365 (Windows 11), VBA 7.1 — last verified 2026-09-04.

Related guides: VBA Like · VBA Regex · VBA CStr · VBA InStr · VBA Split