Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to verify if a string contains valid decimal data

20 views
Skip to first unread message

hbn

unread,
Nov 25, 2011, 8:31:39 AM11/25/11
to
Hi all,

I have some strings that I need to convert to fixed decimal(p, q). The
strings all have type char(100), but p and q will vary based on
different fields in the record.

Before assigning the strings to fixed decimal(p, q) variables I would
like to validate that they are in a proper format, to give som nice
error messages if they are not.

I know I could let the compiler handle this for me, but that gives
warnings in the compiler listing and makes it impossible to give nice
error messages. Therefor I cooked up the following function to
validate if a string can be converted to a fixed decimal value. Please
critique it and give me any pointers on how to do this smarter.

/
*********************************************************************/
validNumeric: proc(s, p, q)
returns(bit(1));

dcl s
char(100);
dcl (p, q) fixed
bin(31);
dcl (first, last, dot) fixed
bin(31);


last = search(s, ' ') -
1;

if last = 0 then
do;
last =
MAXLENGTH(s);

end;


/* remaining string must be blank
*/
if verify(s, ' ', last + 1) > 0 then
do;
put skip list("Multiple spaces
detected");

return('0'b);

end;


if substr(s, 1, 1) = '-'
then
first =
2;

else
first =
1;


dot = search(s,
'.');

if dot < 1
then
dot = last +
1;


if verify(substr(s, first, dot-first), "0123456789") > 0 then
do;
put skip list("Non-digit detected
(part1)");

return('0'b);

end;

if dot < last
&
verify(substr(s, dot+1, last-dot), "0123456789") > 0 then
do;
put skip list("Non-digit detected
(part2)");

return('0'b);

end;

return((p >= (dot-first)) & (q >= (last-
dot)));

end
validNumeric;

/
*********************************************************************/

Note that this will behave slightly different than the compiler:
excess digits before or after the decimal point is considered an error
in the incoming data and need to be reported. Any rounding should
already be done at the time I recieve the data.

Thanks in advance.
Message has been deleted

Robin Vowels

unread,
Nov 26, 2011, 1:52:04 AM11/26/11
to
On Nov 26, 12:31 am, hbn <xxx.greya...@gmail.com> wrote:
> Hi all,
>
> I have some strings that I need to convert to fixed decimal(p, q). The
> strings all have type char(100), but p and q will vary based on
> different fields in the record.
>
> Before assigning the strings to fixed decimal(p, q) variables I would
> like to validate that they are in a proper format, to give som nice
> error messages if they are not.
>
> I know I could let the compiler handle this for me, but that gives
> warnings in the compiler listing and makes it impossible to give nice
> error messages. Therefor I cooked up the following function to
> validate if a string can be converted to a fixed decimal value. Please
> critique it and give me any pointers on how to do this smarter.
>
> Note that this will behave slightly different than the compiler:
> excess digits before or after the decimal point is considered an error
> in the incoming data and need to be reported. Any rounding should
> already be done at the time I recieve the data.
>
> Thanks in advance.

The EDIT function can be used to convert string values.
The TALLY function can be used to count the number of decimal
digits in all or part of a number: First, the string would need to
be
converted using TRANSLATE, to convert all digits to, say, nines
(and leaving the decimal point and sign unchanged).
Then the number of digits before the point (and separately, the
number of digits after the point) can be counted using TALLY, if
required.

I don't understand how warning messages (or any other compiler
messages) could possibly occur when the data involved comes from
the input.

James J. Weinkam

unread,
Nov 26, 2011, 1:31:46 PM11/26/11
to
hbn wrote:
> Hi all,
>
> I have some strings that I need to convert to fixed decimal(p, q). The
> strings all have type char(100), but p and q will vary based on
> different fields in the record.
>
> Before assigning the strings to fixed decimal(p, q) variables I would
> like to validate that they are in a proper format, to give som nice
> error messages if they are not.
>
> I know I could let the compiler handle this for me, but that gives
> warnings in the compiler listing and makes it impossible to give nice
> error messages. Therefor I cooked up the following function to
> validate if a string can be converted to a fixed decimal value. Please
> critique it and give me any pointers on how to do this smarter.
>

Try this:

check: proc(x,i,l,p,q) returns(bin fixed(8) unsigned) reorder;
/* return codes: */
/* 0 Valid number: i=start, l=length, p=integer places, q=decimal places */
/* 1 All blanks */
/* 2 Sign but no digits */
/* 3 Non blank character(s) after valid number */
dcl x char(100),(i,j,l,p,q) bin fixed, (substr,verify) builtin;
i,j=verify(x,' ',1); if j=0 then return(1); /* leading blanks */
if substr(x,j,1)='-' then j+=1; else if substr(x,j,1)='+' then j+=1; /* sign */
if j>100 then return(2); /* no digits */
p=j; j=verify(x,'0123456789',j); if j=0 then j=101; p=j-p; /* integer part */
if j=101 then do; q=0; l=j-i; return(0); end; /* no decimal places */
if substr(x,j,1)='.' then do; /* decimal point */
j+=1; q=j; j=verify(x,'0123456789',j); if j=0 then j=101; q=j-q; /* decimal places */
if j=101 then do; l=j-i; return(0); end;
end;
else q=0;
l=j-i; if verify(x,' ',j)=0 then if p+q>0 then return(0); else return(2); else return(3);
end check;


If your compiler doesn't support the third argument of verify, simply change verify(x,p,j) to
verify(substr(x,j),p);

James J. Weinkam

unread,
Nov 26, 2011, 3:13:49 PM11/26/11
to
James J. Weinkam wrote:
>
> If your compiler doesn't support the third argument of verify, simply change verify(x,p,j) to
> verify(substr(x,j),p);

Sorry this isn't quite correct. If the result of verify is non zero, you also have to increase it by
j-1.

hbn

unread,
Nov 28, 2011, 1:49:50 AM11/28/11
to
I like the idea of using TALLY, could potentially make the last part
of the code more simple.

> I don't understand how warning messages (or any other compiler
> messages) could possibly occur when the data involved comes from
> the input.

The warnings from the compiler appear if you try to assign a char(100)
to a fixed decimal(p, q) variable. The messages warns that the
conversion will be done by an internal compiler routine.I would like
to rid my compiler output of those as I have many lines where this is
needed.

hbn

unread,
Nov 28, 2011, 2:12:17 AM11/28/11
to
On 26 Nov., 19:31, "James J. Weinkam" <j...@cs.sfu.ca> wrote:
>
> Try this:
>
> check: proc(x,i,l,p,q) returns(bin fixed(8) unsigned) reorder;
> /* return codes: */
> /* 0 Valid number: i=start, l=length, p=integer places, q=decimal places */
> /* 1 All blanks */
> /* 2 Sign but no digits */
> /* 3 Non blank character(s) after valid number */
> dcl x char(100),(i,j,l,p,q) bin fixed, (substr,verify) builtin;
> i,j=verify(x,' ',1); if j=0 then return(1); /* leading blanks */
> if substr(x,j,1)='-' then j+=1; else if substr(x,j,1)='+' then j+=1; /* sign */
> if j>100 then return(2); /* no digits */
> p=j; j=verify(x,'0123456789',j); if j=0 then j=101; p=j-p; /* integer part */
> if j=101 then do; q=0; l=j-i; return(0); end; /* no decimal places */
> if substr(x,j,1)='.' then do; /* decimal point */
> j+=1; q=j; j=verify(x,'0123456789',j); if j=0 then j=101; q=j-q; /* decimal places */
> if j=101 then do; l=j-i; return(0); end;
> end;
> else q=0;
> l=j-i; if verify(x,' ',j)=0 then if p+q>0 then return(0); else return(2); else return(3);
> end check;
>
> If your compiler doesn't support the third argument of verify, simply change verify(x,p,j) to
> verify(substr(x,j),p);

Thanks for the answer, it seems this does basically the same thing as
the code I posted, but with a different set of return codes.

Based on the other answers in this thread I gather that you have to
roll your own solution to solve my problem. I guess I was just hoping
for some magical combination of GET EDIT, VALID and some obscure
picture definition could do the trick, maybe the home-rolled solution
is better - at least it's understandable.

Peter Flass

unread,
Nov 28, 2011, 7:45:45 AM11/28/11
to
This message belongs to a group of "performance-oriented" warnings. If
you're trying to wring the most out of your code you'll pay attention,
in most other cases you're thinking "so just do it already." It would
be nice if there were an easy way to enable and disable these as a
group. It might be nice to be able to do this for only particular
sections of code, for example the inner loop of a lengthy computation.

Robin Vowels

unread,
Dec 1, 2011, 1:54:43 AM12/1/11
to
On Nov 26, 12:31 am, hbn <xxx.greya...@gmail.com> wrote:
> Hi all,
>
> I have some strings that I need to convert to fixed decimal(p, q). The
> strings all have type char(100), but p and q will vary based on
> different fields in the record.
>
> Before assigning the strings to fixed decimal(p, q) variables I would
> like to validate that they are in a proper format, to give som nice
> error messages if they are not.
>
> I know I could let the compiler handle this for me, but that gives
> warnings in the compiler listing and makes it impossible to give nice
> error messages. Therefor I cooked up the following function to
> validate if a string can be converted to a fixed decimal value. Please
> critique it and give me any pointers on how to do this smarter.
>
> Note that this will behave slightly different than the compiler:
> excess digits before or after the decimal point is considered an error
> in the incoming data and need to be reported. Any rounding should
> already be done at the time I recieve the data.

I checked out some variations on that theme, shown below.
PL/I will do what you want, without having to write all that code.

test: proc options (main);
declare d fixed (10,5), e fixed (10,6);
declare s character (100) varying;

do d = '-1234.56789', '98.76543212345';
put (d);
end;

s = ' -123.456789876543 ';
d = s;
put skip data (d);
get string (s) list (d);
put skip list (d);
get string (s) edit (d) (f(length(s)));
put skip list (d);

e = s;
d = round(e, 5);
put skip list ('rounded:', d);

s = ' +1234.567898765432123456 ';
d = s;
put skip list (d);
get string (s) edit (d) (f(length(s)));
put skip list (d);
end test;

Results:

-1234.56789 98.76543
D= -123.45678;
-123.45678
-123.45678
rounded: -123.45679
1234.56789
1234.56789

That doesn't check for excessive digits, but TALLY can do
that part for you.

As for nice run-time error messages, something like this will do it:

on conversion begin;
put skip list ('this data has an error: ' || s);
go to discard;
end;
get string (s) list (d);
discard:

That GET statement requires that here is at least one blank at the end
of the number, otherwise, use GET EDIT.

BTW, there were no compilation warning or other messages.

Robin Vowels

unread,
Dec 1, 2011, 1:59:42 AM12/1/11
to
On Nov 28, 11:45 pm, Peter Flass <Peter_Fl...@Yahoo.com> wrote:

> This message belongs to a group of "performance-oriented" warnings.  If
> you're trying to wring the most out of your code you'll pay attention,
> in most other cases you're thinking "so just do it already."

That's right. But in this case, the data conversion (from external to
internal form) must be done at some point, and either it's done by
the I/O routines, or it's done by subroutine. In either case, the
overheads are comparable, and any message about performance is
neither here nor there.

Incidentally, such a message was not produced for the code that I
tried in the preceding post.

Peter Flass

unread,
Dec 1, 2011, 7:39:33 AM12/1/11
to
On 12/1/2011 1:54 AM, Robin Vowels wrote:
>
> As for nice run-time error messages, something like this will do it:
>
> on conversion begin;
> put skip list ('this data has an error: ' || s);
> go to discard;
> end;
> get string (s) list (d);
> discard:
>


I think the OP was trying to avoid the overhead of a CONVERSION On-Unit,
although since this is a software-detected error and not a hardware
interrupt the overhead should be minimal.

Robin Vowels

unread,
Dec 1, 2011, 9:57:47 AM12/1/11
to
I looked at the OP's posts just now, but don't see any mention of
that.
He talked about compilation messages.

I agree that overheads of detecting and recovering from any data
errors would be minimal. Validating first might save a little time
by avoiding the conversion when the data is bad. However, as
validating takes only marginally less time as performing the
conversion, any saving would be not noticeable.

And since the OP wanted to check for excessive number of digits,
that test would probably weed out almost all data errors anyway,
so the likelihood of raising the CONVERSION condition would be
very small.
0 new messages