# GameMaker: Checking whether a string is a valid number Some things are numbers, some aren't

GameMaker Studio 2.2.2 released few days ago, bringing, among improvements, "GML consistency", which changes how automatic type conversion works in corner cases.

A little less known thing, together with that it also changed how GameMaker's string-to-number conversion function (real) works, having it throw an error if your string is definitely not a number.

A slight inconvenience, given that there is not a function to check if a string is a number before attempting conversion.

But, of course, that can be fixed.

## What is a number

For all we know, a string containing a number would have the following structure:

• A minus sign - (optional)
• Zero or more digits
• A period . (optional)
• If period is included, zero or more digits
• Must contain at least 1 digit total
• Must not contain anything else (trim your stirng separately if you must)

Let's break this down in steps,

## An unsigned integer

This one's easy because GameMaker has a built-in string_digits function, which will take a string and return a new string that only contains digits from it ("a4b5" -> "45"). Thus we can utilize this to check whether a string only contains digits (and also that it is not empty):

```/// string_is_uint(string)
var s = argument0;
var n = string_length(string_digits(s));
return n > 0 && n == string_length(s);
```

As we know that string_digits will return the digits in order, a length comparison will suffice.
Nice and easy.

## A signed integer

The only difference between a signed an unsigned integer is that a signed one might have a - in front. So, we need to check that it's either all-digits, or (number of digits - 1) long if there's a -.

As GameMaker allows to implicitly cast true to 1 and false to 0, we can cheat just a little bit:

```/// string_is_int(string)
var s = argument0;
var n = string_length(string_digits(s));
return n > 0 && n == string_length(s) - (string_ord_at(s, 1) == ord("-"));
```

(to be fair, we could also make use of fact that GM's "truthfulness" condition for numbers is num > 0.5 and shorten that to return n && ..., but let's stick to clearer notation here)

## A floating-point number

Things are exactly the same, but! There can now be a dot/period.

So we can simply check if the input contains a ., and further decrease the expected number of digits if that is so:

```/// string_is_real(string)
var s = argument0;
var n = string_length(string_digits(s));
return n > 0 && n == string_length(s) - (string_ord_at(s, 1) == ord("-")) - (string_pos(".", s) != 0);
```

## Exponential notation

Did you know that GameMaker allows exponential notation for values passed to real?

1e3 for 1000 (1*103) or .1e2 for 10 (0.1*102) and such.

Not actively documented or anything.

And I don't suppose you would want to let the user enter such values often either.

But still, if you'd want that,

```/// string_is_real_exp(string)
var s = argument0;
var n = string_length(string_digits(s));
var p = string_pos(".", s);
var e = string_pos("e", s);
switch (e) {
case 0: break; // ok!
case 1: return false; // "e#"
case 2: if (p > 0) return false; break; // ".e#" or "1e."
default: if (p > 0 && e < p) return false; break; // "1e3.3"
}
return n && n == string_length(s) - (string_char_at(s, 1) == "-") - (p != 0) - (e != 0);
```

## Doing it yourself

Suppose you want to do things yourself, without utilizing string_digits. You can do that too,

```/// string_is_real_exp_pure(string)
var s = argument0;
var n = string_byte_length(s);
var seenDot = false;
var seenExp = false;
var numDigs = 0;
var i = 1;
if (string_byte_at(s, 1) == ord("-")) i += 1;
while (i <= n) {
var c = string_byte_at(s, i);
switch (c) {
case ord("."):
if (seenDot || seenExp) return false;
seenDot = true;
break;
case ord("e"): case ord("E"):
if (seenExp || numDigs == 0) return false;
seenExp = true;
break;
default:
if (c >= ord("0") && c <= ord("9")) {
numDigs += 1;
} else return false;
}
i += 1;
}
return numDigs > 0;
```

As a note here, if you are reading this not for GM, pay attention that GML strings have indexes start at 1, so you'll need i = 0, (s, 0), and i < n accordingly.

As a second note, on HTML5 it's beneficial to use string_ord_at+string_length instead of string_byte_at+string_byte_length because JS doesn't work with bytes directly.

Have fun!

### Related posts:

| | No responses 