FUNCTION sfloat, INPUT, exponent=exponent, xfora=xfora, double_p=double_p, $ strvec=StrVEC, fmt=FMT, numfmt=NumFMT, lenfmt=LenFMT, $ strcrumbs=StrCRUMBS, numcrumbs=NumCRUMBS, lencrumbs=LenCRUMBS ;+ ; NAME: ; sfloat ; PURPOSE: ; Extract numbers from string and put them in floating point array ; CATEGORY: ; String processing ; CALLING SEQUENCE: ; FltVEC = sfloat(INPUT,/exponent,strvec=StrVEC,fmt=FMT, xfora=xfora, $ ; numfmt=NumFMT, lenfmt=LenFMT, strcrumbs=StrCRUMBS, $ ; numcrumbs=NumCRUMBS,lencrumbs=LenCRUMBS) ; INPUTS: ; INPUT string (e.g. 89/1/12) ; /exponent if set and nonzero, exponentials of type 'D' and 'E' are ; also interpreted ; /double_p if set then a double precision array is returned ; (default: single precision) ; /xfora ; OUTPUTS: ; FltVEC floating array (e.g. [89,1,12]) ; StrVEC string array (array FltVEC before conversion to float) ; FMT format string matching the input string ; NumFMT # valid numbers located in the input string ; LenFMT # chars taken up by the NumFMT numbers in the input string ; StrCRUMBS string array with part of input string not translated ; into numbers ; NumCRUMBS # elements in StrCRUMBS ; LenCRUMBS # total length of all elements in StrCRUMBS summed ; INCLUDE: @compile_opt.pro ; On error, return to caller ; CALLS: ; boost, BadValue, sfloat ; PROCEDURE: ; Checks each character against a list of valid characters. Processing ; characters sequentially going from first to last, the largest possible ; substrings representing valid numbers are extracted. Only integer ; exponents are accepted (if the keyword /exponent is set). ; MODIFICATION HISTORY: ; Written Jan 1989 by DMZ (ARC) ; Converted to V2 Dec 1990 by DMZ (ARC) ; OCT-1990, Paul Hick (ARC), Expanded to accept exponentials, ; ?-1993, Paul Hick (UCSD), Added construction of format specifiers ; FEB-1995, Paul Hick (UCSD), Added option to pull out the substrings ; not translated into numbers ; MAR-2000, Paul Hick (UCSD), added /double_p keyword ; JUL-2002, Paul Hick (UCSD/CASS) ; Fixed problem for dealing with formatting of peculiar exponents. ; E.g. '(1.dat)' would return format '(D2.-4,A3)'. Now it returns '(D3.0,A2)' ; MAY-2004, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ; Changed strmid(var,2,999) to strmid(var,2) ; (extracts to end of string 'var') ;- n = n_elements(INPUT) IF n GT 1 THEN BEGIN FOR i=0,n-1 DO BEGIN FltVECi = sfloat(INPUT[i], exponent=exponent, xfora=xfora, double_p=double_p, $ strvec=StrVECi, fmt=FMTi,numfmt=NumFMTi,lenfmt=LenFMTi, $ strcrumbs=StrCRUMBSi,numcrumbs=NumCRUMBSi,lencrumbs=LenCRUMBSi ) boost, /push, FltVEC, FltVECi boost, /push, StrVEC, StrVECi boost, /push, FMT , FMTi boost, /push, NumFMT, NumFMTi boost, /push, LenFMT, LenFMTi boost, /push, StrCRUMBS, StrCRUMBSi boost, /push, NumCRUMBS, NumCRUMBSi boost, /push, LenCRUMBS, LenCRUMBSi ENDFOR RETURN, FltVEC ENDIF InitVar, double_p, /key InitVar, exponent, /key InitVar, xfora , /key VALID_NR = ['1','2','3','4','5','6','7','8','9','0'] VALID_NRDOT = [VALID_NR,'.'] VALID_EXP = [VALID_NR,'+','-'] VALID_FULL = [VALID_NR,'.','+','-'] cStr = strtrim(INPUT[0]) Len = strlen(cStr) I = -1 CASE double_p OF 0: FltVEC = BadValue(0.0) 1: FltVEC = BadValue(0.0d0) ENDCASE StrVEC = '' FMT = '*' NumFMT = 0 FMTCNT = 0 LenFMT = 0 NumCRUMBS = 0 LenCRUMBS = 0 LAST = I ; End of previous number BLANKS = 0 FIRST_CHAR: I = I+1 IF I GE Len THEN goto, DONE CH = strmid(cStr,I,1) IF CH EQ ' ' THEN BEGIN BLANKS = BLANKS+1 goto, FIRST_CHAR ENDIF A = where(CH EQ VALID_FULL,cNum) ; First char must be +,-,. or digit IF cNum EQ 0 THEN BEGIN BLANKS = 0 goto, FIRST_CHAR ENDIF FIRST = -1 IF CH EQ '+' OR CH EQ '-' THEN BEGIN J = I+1 ; Position following +,- IF J GE Len THEN BEGIN I = J goto, DONE ENDIF CH = strmid(cStr,J,1) A = where(CH EQ VALID_NRDOT,cNum) ; +,- must be followed by . or digit IF cNum EQ 0 THEN BEGIN BLANKS = 0 goto, FIRST_CHAR ENDIF FIRST = I ; Position of +,- (start of number) I = J ; Position of . or digit ENDIF IF CH EQ '.' THEN BEGIN J = I+1 ; Position following . if J ge Len then begin I = J goto, DONE endif CH = strmid(cStr,J,1) A = where(CH eq VALID_NR,cNum) ; . must be followed by number if cNum eq 0 then begin BLANKS = 0 goto, FIRST_CHAR endif DOT = I ; Position of . FMTCHAR = 'F' if FIRST eq -1 then FIRST = I ; Start of number I = J ; Position of digit endif else DOT = -1 if FIRST eq -1 then FIRST = I ; Start of number FIRST = FIRST-BLANKS ; Include blanks preceding number in format BLANKS = 0 ; Clear blanks counter if FIRST gt LAST+1 then begin case FMTCNT of 0: FMTL = 0 1: FMT = FMT+','+FMTSUB else: FMT = FMT+','+strcompress(FMTCNT,/remove_all)+FMTSUB endcase LenFMT = LenFMT+FMTCNT*FMTL A = FIRST-LAST-1 FMTCNT = 0 case xfora of 0: FMT = FMT+',A'+strcompress(A,/remove_all) 1: FMT = FMT+','+strcompress(A,/remove_all)+'X' endcase NumCRUMBS = NumCRUMBS+1 LenCRUMBS = LenCRUMBS+A A = strmid(cStr,LAST+1,A) case NumCRUMBS of 1 : StrCRUMBS = A else: StrCRUMBS = [StrCRUMBS,A] endcase endif ; At this point the first digit is located (possibly preceded by +,+.,- or -.) ; i.e. a valid number has been located (as yet incomplete) ; FIRST = position where number starts ; DOT = position of . (-1 if no . was found) ; I = position of first digit ; Now start looking for the end of the number LAST_CHAR: I = I+1 if I ge Len then goto, NUMBER CH = strmid(cStr,I,1) if DOT eq -1 and CH eq '.' then begin ; . is acceptable if it's the first one DOT = I FMTCHAR = 'F' goto, LAST_CHAR endif A = where(CH eq VALID_NR,cNum) ; only digits are acceptable if cNum gt 0 then goto, LAST_CHAR ; if the keyword 'exponent' is not set then the number is considered completed. ; if the keyword 'exponent' is set then continue only if the letter D or E is found ; If the number is complete then I is the position following the number if not exponent or (CH ne 'D' and CH ne 'E' and CH ne 'd' and CH ne 'e') then goto, NUMBER FMTCHAR = strupcase(CH) ; Analyze exponent IES = I ; Position of D,E I = IES+1 if I ge Len then goto, NUMBER CH = strmid(cStr,I,1) A = where(CH eq VALID_EXP,cNum) ; D,E must be followed by +,- or number if cNum eq 0 then goto, NUMBER IE = I if CH eq '+' or CH eq '-' then begin; If IE is position of +,- J = IE+1 ; Position following +,- if J ge Len then goto, NUMBER CH = strmid(cStr,J,1) A = where(CH eq VALID_NR,cNum) ; +,- must be followed by number if cNum eq 0 then goto, NUMBER IE = J ; Position of digit endif I = IE ; first digit in exponent located ; (possibly preceded by + or -) LAST_CHAR_EXP: I = I+1 if I ge Len then goto, NUMBER CH = strmid(cStr,I,1) A = where(CH eq VALID_NR,cNum) ; only numbers are acceptable if cNum gt 0 then goto, LAST_CHAR_EXP NUMBER: StrVAL = strmid(cStr,FIRST,I-FIRST) case double_p of 0: FltVAL = float (StrVAL) 1: FltVAL = double(StrVAL) endcase if StrVEC[0] eq '' then begin StrVEC = StrVAL FltVEC = FltVAL endif else begin StrVEC = [StrVEC,StrVAL] FltVEC = [FltVEC,FltVAL] endelse NumFMT = NumFMT+1 if DOT eq -1 then FMTCHAR = 'I' ;if DOT eq -1 then FMTCHAR = 'F' if DOT eq -1 then DOT = I-1 FMTNEW = FMTCHAR + strcompress(I-FIRST,/remove_all) case FMTCHAR of 'F': FMTNEW = FMTNEW + '.' + strcompress(I- DOT-1 > 0,/remove_all) 'D': FMTNEW = FMTNEW + '.' + strcompress(IES-DOT-1 > 0,/remove_all) 'E': FMTNEW = FMTNEW + '.' + strcompress(IES-DOT-1 > 0,/remove_all) else: FMTNEW = FMTNEW endcase if FMTCNT eq 0 then begin FMTSUB = FMTNEW FMTCNT = 1 FMTL = I-FIRST endif else if FMTNEW eq FMTSUB then $ FMTCNT = FMTCNT+1 $ else begin case FMTCNT of 1: FMT = FMT+','+FMTSUB else: FMT = FMT+','+strcompress(FMTCNT,/remove_all)+FMTSUB endcase LenFMT = LenFMT+FMTCNT*FMTL FMTSUB = FMTNEW FMTL = I-FIRST FMTCNT = 1 endelse I = I-1 LAST = I ; Pos of last character processed goto, FIRST_CHAR DONE: case FMTCNT of 0: FMTL = 0 1: FMT = FMT+','+FMTSUB else: FMT = FMT+','+strcompress(FMTCNT,/remove_all)+FMTSUB endcase LenFMT = LenFMT+FMTCNT*FMTL if I gt LAST+1 then begin A = I-LAST-1 case xfora of 0: FMT = FMT+',A'+strcompress(A,/remove_all) 1: FMT = FMT+','+strcompress(A,/remove_all)+'X' endcase NumCRUMBS = NumCRUMBS+1 LenCRUMBS = LenCRUMBS+A A = strmid(cStr,LAST+1,A) case NumCRUMBS of 1 : StrCRUMBS = A else: StrCRUMBS = [StrCRUMBS,A] endcase endif FMT = strmid(FMT,2) FMT = '('+FMT+')' RETURN, FltVEC & END