valid_num.pro 4.66 KB
;+
; NAME: 
;     VALID_NUM
; PURPOSE:               
;     Check if a string is a valid number representation.
; EXPLANATION:              
;     The input string is parsed for characters that may possibly
;     form a valid number.  It is more robust than simply checking
;     for an IDL conversion error because that allows strings such
;     as '22.3qwert' to be returned as the valid number 22.3
;     See also the original NUM_CHK which returns the status in 
;     the opposite sense.
;
; CALLING SEQUENCE: 
;     IDL> status = valid_num(string  [,value]  [,/integer])
;    
; Inputs      : string  -  the string to be tested
;               
; Opt. Inputs : None
;               
; Outputs     : The function returns 1 for valid, 0 for invalid number
;               
; Opt. Outputs: value	- The value the string decodes to.  This will be
;			  returned as a double precision number unless /INTEGER
;			  is present, in which case a long integer is returned.
;               
; Keywords    : Integer   -  if present code checks specifically for an integer.
;
; Calls       : None
;               
; Restrictions: None
;               
; Category    : Utilities, Numerical
;               
; Prev. Hist. : Small changes from NUM_CHK by Andrew Bowen, 
;                                             Tessella Support Services, 8/3/93
;
; Written     : CDS version by C D Pike, RAL, 24-May-93
;               
; Modified    : Version 1, C D Pike, RAL, 24-May-93
;		Version 2, William Thompson, GSFC, 14 October 1994
;			Added optional output parameter VALUE to allow
;			VALID_NUM to replace STRNUMBER in FITS routines.
;
; Version     : Version 1  24-May-93
;	Converted to IDL V5.0   W. Landsman   September 1997
;-            

FUNCTION valid_num, string, value, INTEGER=integer

		;**** Set defaults for keyword ****
  IF NOT (KEYWORD_SET(integer)) THEN integer=0

		;**** arrays of legal characters ****
  numbers 	= '0123456789'
  signs 	= '+-'
  decimal 	= '.'
  exponents 	= 'ED'

		;**** trim leading and trailing blanks/compress white ****
		;**** space and convert any exponents to uppercase.   ****
  numstr = strupcase(strtrim(strcompress(string),2))

		;**** length of input string ****
  len = strlen(numstr)

  ok = 1

  if integer eq 0 then stage = 1 else stage = 6

  for i = 0, len-1 do begin

    char = strmid(numstr,i,1)

		;**** the parsing steps 1 to 8 are for floating   ****
		;**** point, steps 6 to 8, which test for a legal ****
		;**** exponent, can be used to check for integers ****

;**** The parsing structure is as follows.  Each character in the ****
;**** string is checked against the valid list at the current     ****
;**** stage.  If no match is found an error is reported.  When a  ****
;**** match is found the stage number is updated as indicated     ****
;**** ready for the next character.  The valid end points are     ****
;**** indicated in the diagram.					  ****
;
;Stage	1		2		3		4
;
;Valid	sign	--> 2	dec-pt	--> 3	digit	--> 5	dec-pt	--> 5
;  "	dec-pt	--> 3	digit	--> 4			digit	--> 4
;  "	digit	--> 4					exp't	--> 6
;  "							END
;
;Stage	5		6		7		8
;
;Valid	digit	--> 5	sign	--> 7	digit	--> 8	digit	-->8
;  "	exp't	--> 6	digit	--> 8			END
;  "	END
;

    CASE stage OF

      1 : begin
        if 		strpos(signs,char) ge 0 	then stage = 2 $
	else if 	decimal eq char 		then stage = 3 $
	else if 	strpos(numbers,char) ge 0 	then stage = 4 $
	else 		ok = 0
      end

      2 : begin
	if	 	decimal eq char 		then stage = 3 $
	else if 	strpos(numbers,char) ge 0 	then stage = 4 $
	else 		ok = 0
      end

      3 : begin
	if	 	strpos(numbers,char) ge 0 	then stage = 5 $
	else 		ok = 0
      end

      4 : begin
	if	 	decimal eq char 		then stage = 5 $
	else if 	strpos(numbers,char) ge 0 	then stage = 4 $
	else if		strpos(exponents,char) ge 0	then stage = 6 $
	else 		ok = 0
      end

      5 : begin
	if	 	strpos(numbers,char) ge 0 	then stage = 5 $
	else if		strpos(exponents,char) ge 0	then stage = 6 $
	else 		ok = 0
      end

      6 : begin
        if 		strpos(signs,char) ge 0 	then stage = 7 $
	else if 	strpos(numbers,char) ge 0 	then stage = 8 $
	else 		ok = 0
      end

      7 : begin
	if	 	strpos(numbers,char) ge 0 	then stage = 8 $
	else 		ok = 0
      end

      8 : begin
	if	 	strpos(numbers,char) ge 0 	then stage = 8 $
	else 		ok = 0
      end

    ENDCASE

  end

		;**** check that the string terminated legally ****
		;**** i.e in stages 4, 5 or 8                  ****
  if (stage ne 4) and (stage ne 5) and (stage ne 8) then ok = 0

		;**** If requested, then form the value. ****

  if (n_params() eq 2) and ok then begin
	if keyword_set(integer) then value = long(string) else	$
		value = double(string)
  endif

		;**** return error status to the caller ****
  RETURN, ok


END