Parsing Strings Into Numbers

Overview

Numbers in Oracle CPQ are often stored as strings. In order to perform any calculations with these values, the data must first be parsed into a number.

Parsing data can be error prone. By being thorough and type-checking our data, we can create flexible solutions that behave reasonably when dealing with invalid inputs.

Number parsing may come into play in BML, JavaScript, XSL, or any other scripting or programming language that passes data around or accepts user input. This article focuses on the mechanisms used within BML.

Administration

There are two BML functions that directly convert a string into a number:

parsedInteger = atoi("1");
parsedFloat = atof("1.1");

These functions provide a useful function, but can raise errors when used directly without type-checking first. For instance, consider the following inputs:

parsedInteger = atoi("");
parsedFloat = atof("1.1%");

Passing in these non-numeric strings will cause the functions to throw "invalid literal" errors.

ClosedUsing isnumber

To deal with this, the isnumber function is available. This function takes a string, and returns true if the string can be converted into a float.

This function can help you identify invalid data; it is up to you to determine the best way to handle invalid inputs. Out of the box, isnumber is all that you need to safely use the atof function:

value = "1.0";
new_value = 0;
if(isnumber(value)) {
// conversion will only occur if the value is safe
new_value = atof(value);
}

However, isnumber() is not sufficient when using atoi. Consider the following:

value = "1.0";
new_value = 0;
if(isnumber(value)) {
// "1.1" will pass the isnumber check, but is an invalid input for atoi
new_value = atoi(value);
}

Because of this drawback, best practice is to never use atoi. Instead, use the safer atof function, in conjunction with isnumber. To get an integer, you can then caste the float value using the integer function:

value = "1.0";
new_value = 0;
if(isnumber(value)) {
//safely caste to integer, after translating to float
new_value = integer(atof(value));
}
Use util libraries to wrap up these tests for you; it makes for cleaner code and is easier to maintain.

ClosedcustomAtoi Util Library

/*
BML util (customAtoi)
- To convert the string into integer.
- if the input is not a valid number, the application will take the default value input and return back as a result.
param:
inputValue - String
defaultValue - integer
result:
Integer
*/
result = defaultValue;
if ( isnumber(inputValue) ) {
result = integer(atof(inputValue));
}
return result;
Usage
//returns integer 1
value = util.customAtof("1.1", "Invalid Value");
//returns error value "Invalid Value"
value = util.customAtof("1%", "Invalid Value");

ClosedcustomAtof Util Library


Troubleshooting

Using these safe methods of parsing numbers will keep errors from occurring in the face of invalid data. But this doesn't mean that your problems are over. There is a reason that the data was invalid to begin with, and it is up to you to determine if that is a serious problem, and what to do about it.

Sometimes it may be appropriate to "throw" an error, so that the admin or other people maintaining the site will have visibility to the problem. An effective way to do this is to write into a validation attribute.

This is simple to accomplish: in your advanced modification function, write into a text attribute. In the advance validation function, check that function and show an error if there is any value in it.

An example of this technique in an advanced modify function:

...
int_value = customAtoi(value, "There was an invalid input for value: " + value);
if(!isnumber(int_value) {
resultString = resultString + "1~validationMessage_quote~" + int_value;
}
...
In the advanced validation:
...
resultString = resultString + validationMessage_quote;
...

Related Topics

Related Topics Link IconSee Also