# String To Number Conversion With Proper Error Detection

## Recommended Posts

I have written these functions because IMO the standard AutoIt conversion function called 'Number()' is inadequate, e.g. it just stops conversion when a non-digit character is found. If _any_ kind of badly formed string is found, the function should report an error and abort conversion. Also 'Number() does not distinguish integers and floats which may be important in certain situations, and it cannot convert binary or hexadecimal strings.

My functions are intended for situations when error reporting is important (e.g. manual input or reading values from a text file). If you are absolutely sure that there will be no errors in the number format then you can use 'Number(). But can you ever be absolutely sure?

At the end of this post, in separate code sections, there are to simple test scripts to demostrate how these functions work.

Description of functions:

StringToInt(str, base)

Converts the string 'str' to an integer using the number base 'base' (2, 10 or 16). Returns the converted value. In case of error the return value is zero. Sets '@error' as follows:

0 = no error

-2 = string too long or too short

-3 = string contains non-digit character(s)

StringToFloat(str)

Converts the string 'str' to a floating point number.

Accepts the following formats ('n' represents one or more decimal digits):

n -n .n -.n n. -n. n.n -n.n

nEn nE-n -nEn -nE-n n.nEn -n.nEn n.nE-n -n.nE-n

There must be at most 3 digits in the exponent, and its absolute value must not be larger than 300. The maximum number of characters in 'str' is 22 (sufficient for 15-digit precision in the longest format with full exponent and two minus signs).

Returns the converted value. In case of error returns zero. Sets '@error' as follows:

0 = no error

-2 = string too long or too short

-3 = non-digit character where digit is expected

-4 = formatting error (not a proper floating point number)

Formatting errors (code -4) include:

- neither integer nor fractional part present

- decimal point is after the exponent mark 'E'

- minus sign is in bad position (not the first char in exponent)

- multiple decimal points

- multiple exponent marks 'E'

- Exponent marker 'E' without exponent digits

- too many digits in exponent

- exponent value too big (> 300)

```; numconv.au3
;
; String to number conversion with proper error detection and reporting.
;
; AutoIt Version: 3.0
; Language:    English
; Platform:    Win9x/NT
; Author:        Laszlo Menczel (menczel@invitel.hu)
; Date:        4/9/2006
;
; Include this file at the start of your script (use 'include-once').

; Exp10(pow)
; Helper function to calculate power of 10 (for exponent values).
; WARNING: This is NOT a general purpose function, it works only with integer arguments!

Func Exp10(\$pow)

Dim \$i, \$res, \$x

\$x = Round(\$pow)

If \$x = 0 Then
Return 1
Endif

\$res = 1;

If \$x > 0 Then
For \$i = 1 TO \$x
\$res = 10.0 * \$res
Next
Else
\$x = -1 * \$x
For \$i = 1 TO \$x
\$res = \$res / 10.0
Next
Endif

Return \$res

EndFunc

;-------------------------------------------------------------------------------

; CharToNumber(chr, digits)
; Helper function to get the numeric value of a character interpreted
; as a digit. Valid characters are specified in 'digits'.

Func CharToNumber(\$chr, \$dig)

Dim \$pos, \$next, \$len

\$len = StringLen(\$dig)
\$pos = 1

While \$pos <= \$len

\$next = StringMid(\$dig, \$pos, 1)
If \$chr = \$next Then
Return \$pos - 1
Endif

\$pos = \$pos + 1
Wend

Return -1

EndFunc

;-------------------------------------------------------------------------------

Func StringToInt(\$s, \$base)

Dim \$pos, \$len, \$maxlen, \$val, \$tmp
Dim \$fact, \$mult, \$sum, \$sign, \$digits, \$start

If \$s = "" Then
SetError(-1)
Return 0
Endif

If \$base <> 2 AND \$base <> 10 AND \$base <> 16 Then
SetError(-1)
Return 0
Endif

\$start = 1
\$sign = 1

Select

Case \$base = 2
\$mult = 2
\$maxlen = 32
\$digits = "01"

Case \$base = 10
\$mult = 10
\$maxlen = 10
\$digits = "0123456789"

\$tmp = StringMid(\$s, 1, 1)
If \$tmp = "-" Then
\$maxlen = \$maxlen + 1
\$start = 2
\$sign = -1
Endif

Case \$base = 16
\$mult = 16
\$maxlen = 8
\$digits = "0123456789ABCDEF"

EndSelect

\$pos = StringLen(\$s)
If \$pos > \$maxlen OR (\$pos - \$start) < 1 Then
SetError(-2)
Return 0
Endif

\$fact = 1
\$sum = 0

While \$pos >= \$start

\$tmp = StringMid(\$s, \$pos, 1)
\$val = CharToNumber(\$tmp, \$digits)

If \$val = -1 Then
SetError(-3)
Return 0
Endif

\$sum = \$sum + \$fact * \$val
\$fact = \$fact * \$mult
\$pos = \$pos - 1

Wend

\$sum = \$sum * \$sign

SetError(0)
Return \$sum

EndFunc

;-------------------------------------------------------------------------------

Func StringToFloat(\$s)

Dim \$tmp, \$val, \$factor, \$len, \$pos, \$start, \$digits
Dim \$int_present, \$frac_present, \$exp_present
Dim \$dotpos, \$fracval, \$intval, \$sign
Dim \$exppos, \$expbeg, \$expval, \$expsign

;--------- check argument

If \$s = "" Then
SetError(-1)
Return 0.0
Endif

\$len = StringLen(\$s)

If \$len < 1 OR \$len > 22 Then
SetError(-2)
Return 0.0
Endif

;----------- initialize variables

\$sum = 0.0
\$sign = 1.0
\$expsign = 1.0
\$expval = 0.0
\$fracval = 0.0
\$intval = 0.0

\$int_present = 0
\$frac_present = 0
\$exp_present = 0

\$start = 1
\$digits = "0123456789"

;----------- scan string & collect info

\$tmp = StringMid(\$s, 1, 1)       ; check for minus sign

If \$tmp = "-" Then
If \$len < 2 Then               ; no digits
SetError(-2)
Return 0.0
Else
\$sign = -1.0
\$start = 2
Endif
Endif

\$dotpos = 0
\$exppos = \$len + 1
\$pos = \$start

While \$pos <= \$len

\$tmp = StringMid(\$s, \$pos, 1)

Select
Case \$tmp = "."
If \$dotpos > 0 Then      ; multiple decimal points
SetError(-4)
Return 0.0
Else
\$dotpos = \$pos
Endif

Case \$tmp = "e"              ; multiple exponent markers
If \$exppos < \$len + 1 Then
SetError(-4)
Return 0.0
Else
\$exppos = \$pos
Endif

EndSelect

\$pos = \$pos + 1

Wend

;----------- check positions & set flags

If \$dotpos > \$exppos Then
SetError(-4)
Return 0.0
Endif

If \$exppos < \$len + 1 Then

\$expbeg = \$exppos

If \$expbeg = \$len Then       ; no exponent spec
SetError(-4)
Return 0.0
Endif

\$tmp = StringMid(\$s, \$expbeg + 1, 1)

If \$tmp = "-" Then           ; check for minus sign
\$expbeg = \$expbeg + 1
If \$expbeg = \$len Then       ; no digits
SetError(-4)
Return 0.0
Else
If (\$len - \$expbeg) > 3 Then ; too many digits
SetError(-4)
Return 0.0
Else
\$expsign = -1.0
Endif
Endif
Endif

\$exp_present = 1

Endif

If \$dotpos > 0 Then              ; decimal point present
If (\$exppos - \$dotpos) > 1 Then
\$frac_present = 1
Endif
If (\$dotpos - \$start) > 0 Then
\$int_present = 1
Endif
Else                            ; only integer part if any
If (\$exppos - \$start) > 0 Then
\$int_present = 1
Endif
Endif

If \$int_present = 0 AND \$frac_present = 0 Then
SetError(-4)
Return 0.0
Endif

;----------- convert the exponent if present

If \$exp_present > 0 Then

\$pos = \$len
\$factor = 1.0
\$expval = 0.0

While \$pos > \$expbeg

\$tmp = StringMid(\$s, \$pos, 1)
\$val = CharToNumber(\$tmp, \$digits)

If \$val < 0 Then
SetError(-3)
Return 0.0
Else
\$expval = \$expval + \$val * \$factor
\$factor = 10.0 * \$factor
Endif

\$pos = \$pos - 1

Wend

If \$expval > 300 Then
SetError(-4)
Return 0.0
Endif

Endif

;----------- convert fractional part if present

If \$frac_present > 0 Then

\$pos = \$dotpos + 1
\$factor = 0.1

While \$pos < \$exppos

\$tmp = StringMid(\$s, \$pos, 1)
\$val = CharToNumber(\$tmp, \$digits)

If \$val < 0 Then
SetError(-3)
Return 0.0
Else
\$fracval = \$fracval + \$val * \$factor
\$factor = \$factor / 10.0
Endif

\$pos = \$pos + 1

Wend

Endif

;------------ convert integer part if present

If \$int_present > 0 Then

If \$dotpos > 0 Then
\$pos = \$dotpos - 1
Else
\$pos = \$exppos - 1
Endif

\$factor = 1.0

While \$pos >= \$start

\$tmp = StringMid(\$s, \$pos, 1)
\$val = CharToNumber(\$tmp, \$digits)

If \$val < 0 Then
SetError(-3)
Return 0.0
Else
\$intval = \$intval + \$val * \$factor
\$factor = \$factor * 10.0
Endif

\$pos = \$pos - 1

Wend

Endif

;------------ calculate & return the final value

\$val = \$sign * (\$intval + \$fracval) * Exp10(\$expsign * \$expval)
SetError(0)
Return \$val

EndFunc```

```; Script to test StringToInt()

#include <GUIConstants.au3>
#include "numconv.au3"

Opt("ExpandVarStrings", 1)
Opt("RunErrorsFatal", 0)

\$tmp = InputBox("Number base", "2, 10 or 16:")
\$x = Number(\$tmp)

If \$x <> 2 AND \$x <> 10 AND \$x <> 16 Then
\$str = StringFormat("bad number base %s", \$tmp)
MsgBox(0, "Error", \$str)
Exit
Endif

\$tmp = InputBox("Input", "String to convert:")
\$val = StringToInt(\$tmp, \$x)

If @error = 0 Then
\$tmp = StringFormat("value = %d", \$val)
MsgBox(0, "Result", \$tmp)
Else
\$tmp = StringFormat("error %d", @error)
MsgBox(0, "Result", \$tmp)
Endif

Exit```

```; Script to test StringToFloat()

#include <GUIConstants.au3>
#include "numconv.au3"

Opt("ExpandVarStrings", 1)
Opt("RunErrorsFatal", 0)

\$tmp = InputBox("Input", "String to convert:")
\$val = StringToFloat(\$tmp)

If @error = 0 Then
\$tmp = StringFormat("value = %f", \$val)
MsgBox(0, "Result", \$tmp)
Else
\$tmp = StringFormat("error %d", @error)
MsgBox(0, "Result", \$tmp)
Endif

Exit```

##### Share on other sites

hi,

I would line to ask you it you pay attention that the decimal separator can be different than the dot "." in other countries ?

Here it's the coma "," for example.. i don't know if it can be modified easily ?

Cya

##### Share on other sites

nice function.

@Jango

If you look through the script you could easily change the '.' to a ',' or add in a stringreplace that changes the ',' to a '.'

My Programs:AInstall - Create a standalone installer for your programUnit Converter - Converts Length, Area, Volume, Weight, Temperature and Pressure to different unitsBinary Clock - Hours, minutes and seconds have 10 columns each to display timeAutoIt Editor - Code Editor with Syntax Highlighting.Laserix Editor & Player - Create, Edit and Play Laserix LevelsLyric Syncer - Create and use Synchronised Lyrics.Connect 4 - 2 Player Connect 4 Game (Local or Online!, Formatted Chat!!)MD5, SHA-1, SHA-256, Tiger and Whirlpool Hash Finder - Dictionary and Brute Force FindCool Text Client - Create Rendered ImageMy UDF's:GUI Enhance - Enhance your GUIs visually.IDEA File Encryption - Encrypt and decrypt files easily! File Rename - Rename files easilyRC4 Text Encryption - Encrypt text using the RC4 AlgorithmPrime Number - Check if a number is primeString Remove - remove lots of strings at onceProgress Bar - made easySound UDF - Play, Pause, Resume, Seek and Stop.

## Create an account

Register a new account

×

• Wiki

• Back

• Git