Erlang Central

String Is Valid Number

Revision as of 22:09, 11 September 2006 by 213.171.204.166 (Talk)

Problem

You need to check if a given string contains a valid number.

Solution

We suppose that we want to check the text strings: "42", "2+3i", "3.1416", "2/3", "hello". Erlang is trickier than Scheme, since it does not provide the native support for fractional values or imaginary numbers. However, the general algorithm we need to use is something like the following: 1 Try to convert the string to a number (of some kind). 2 Pass the resulting value to the built-in Erlang predicates is_number.

Let's see some examples:

1> is_number("42").
false
2> {ok, [Num], _} = io_lib:fread("~d", "42"), is_number(Num).
true
3> {ok, [Num2], _} = io_lib:fread("~u", "42"), is_number(Num2).
true
4> {ok, [Num3], _} = io_lib:fread("~u", "42"), is_number(Num3).
true
5> {ok, [Num4], _} = io_lib:fread("~u", "42.0"), is_number(Num4).
true
6> {ok, [Num5], _} = io_lib:fread("~f", "42.0"), is_number(Num5).
true
7> io_lib:fread("~u", "2+3i").    
{ok,[2],"+3i"}
8> {ok, [Num6], _} = io_lib:fread("~f", "3.1416"), is_number(Num6). 
true
9> io_lib:fread("~f", "2/3").    
{error,{fread,float}}
10> io_lib:fread("~f", "hello").
{error,{fread,float}}

Discussion

Clearly, Erlang's generic io_lib:fread functionality does not provide everything we want. It doesn't handle fractional values with the easy and grace of Scheme, and it does not understand imaginary numbers. However, this functionality could be provided in a library that provides an "is_number" interface similar to what we want.

We could also follow the Perl approach of using regular expressions to determine if the string is a number, but that is a topic for another Recipe.

There may also be times when you want to tell if a given number is an integer number a floating-point number. One solution is using the io_lib:fread function as before, and then using one of the Erlang built-in predicates is_integer and is_float. procedures:

13> {ok, [Val13], _} = io_lib:fread("~f", "3.0"), is_integer(Val13).
false
14> {ok, [Val14], _} = io_lib:fread("~f", "3.0"), is_float(Val14).
true
15> {ok, [Val15], _} = io_lib:fread("~u", "22"), is_integer(Val15).
true