BookmarkSubscribeRSS Feed
G_I_Jeff
Obsidian | Level 7

I need to convert non SAS character input to calculated size numeric, and I can't find my mistake(s):

data _null_;                                          
 input space $11.;                                    
 size=inputn(space,cats('comma',length(space)-1,'.'));
 select (char(space,length(space)));                  
  when ('k') size=size*1000;                          
  when ('m') size=size*1000**2;                       
  when ('g') size=size*1000**3;                       
  otherwise do;                                       
    put 'space not recognized= ' space;               
    abort abend 055;                                  
    end;                                              
 end;                                                 
cards;                                                
 23436.000K                                           
     0.000K                                           
    50.688K                                           
  1340.160M                                           
   837.600K                                           
    47.190K                                           
  1187.640M                                           
    55.872K                                           
 ;                                                    
run;                                                  

I have pieced this together with other code. I'm not the strongest SAS coder. The INPUTN function seems to work the way I need it to. Simply remove the trailing size identifier and convert to numeric. The problem lies in the SELECT, it puts the first SPACE card without trailing identifier. What am I doing wrong?

12 REPLIES 12
Astounding
PROC Star

"k" and "K" are not the same thing.  Easy to correct though.

G_I_Jeff
Obsidian | Level 7

Correct. Still does not resolve the issue.

What I receive:

SPACE NOT RECOGNIZED= 23436.000

Astounding
PROC Star

OK, rather than picking this apart and trying to diagnose where it went wrong, why not make your life easy?

 

input space 10.  magnitude $ 11;

ballardw
Super User

Including ABORT statements for a condition you are asking about is sort of counterproductive as your code kills any chance of seeing what is happening with the data.

 

data junk;                                          
 input space $11.;                                    
 size=inputn(space,cats('comma',length(space)-1,'.'));
 select (char(space,length(space)));                  
  when ('k','K') size=size*1000;                          
  when ('m','M') size=size*1000**2;                       
  when ('g','G') size=size*1000**3;                       
  otherwise do;                                       
    put 'space not recognized= ' space;               
/*    abort abend 055;                                  */
    end;                                              
 end;                                                 
cards;                                                
 23436.000K                                           
     0.000K                                           
    50.688K                                           
  1340.160M                                           
   837.600K                                           
    47.190K                                           
  1187.640M                                           
    55.872K                                           
 ;                                                    
run;       

Or Upcase the result of the Char.

 

 

G_I_Jeff
Obsidian | Level 7

ballardw,

 

Thanks for the input. I would think that this gets me close to what I need but when I run your code it flags all CARD inputs in the OTHERWISE statement. In my logic, it shouldn't be hitting the OTHERWISE statement with the inputs set here.

 

I need the program to stop processing when it encounters anything other than a K,M or G for the suffix. Is this the wrong way to code it?

Tom
Super User Tom
Super User

Your data has an uppercase K but that character it is not listed in any of the values in your WHEN statements.  Also don't abort your whole SAS session just because of one unexpected value.

data test;                                          
 input space $11.;                                    
 size=inputn(space,cats('comma',length(space)-1,'.'));
 select (lowcase(char(space,length(space))));                  
  when ('k') size=size*1000;                          
  when ('m') size=size*1000**2;                       
  when ('g') size=size*1000**3;                       
  otherwise do;      
    invalid=1;
    put 'Suffix not recognized ' space=$quote.;               
  end;                                              
 end;                                                 
cards;                                                
 23436.000K                                           
     0.000K                                           
    50.688K                                           
  1340.160M                                           
   837.600K                                           
    47.190K                                           
  1187.640M                                           
    55.872K   
123A 
;                                                    

proc print;
  format size comma20.;
run;
Obs    space                         size    invalid

 1     23436.000K              23,436,000       .
 2     0.000K                           0       .
 3     50.688K                     50,688       .
 4     1340.160M            1,340,160,000       .
 5     837.600K                   837,600       .
 6     47.190K                     47,190       .
 7     1187.640M            1,187,640,000       .
 8     55.872K                     55,872       .
 9     123A                           123       1
G_I_Jeff
Obsidian | Level 7

Thanks for the input Tom. I believe you were the one that initially helped me with this code. But when I run your exact code below (on a mainframe) it flags all the input cards as invalid and is not calculating the size. I also need this program to stop/end/abort if it encounters anything other than a K,M or G suffix.

OBS    SPACE                        SIZE    INVALID
                                                   
 1     23436.000                  23,436       1   
 2     0.000                           0       1   
 3     50.688                         51       1   
 4     1340.160                    1,340       1   
 5     837.600                       838       1   
 6     47.190                         47       1   
 7     1187.640                    1,188       1   
 8     55.872                         56       1   
 9     123A                          123       1   
G_I_Jeff
Obsidian | Level 7
SUFFIX NOT RECOGNIZED SPACE="23436.000"
SUFFIX NOT RECOGNIZED SPACE="0.000"    
SUFFIX NOT RECOGNIZED SPACE="50.688"   
SUFFIX NOT RECOGNIZED SPACE="1340.160" 
SUFFIX NOT RECOGNIZED SPACE="837.600" 
SUFFIX NOT RECOGNIZED SPACE="47.190"  
SUFFIX NOT RECOGNIZED SPACE="1187.640"
SUFFIX NOT RECOGNIZED SPACE="55.872"  
SUFFIX NOT RECOGNIZED SPACE="123A"    
G_I_Jeff
Obsidian | Level 7

There is something with positioning on the mainframe. I ran the following, with the inputs aligned under the CARDS statement:

data test;                                            
 input space $11.;                                    
 size=inputn(space,cats('comma',length(space)-1,'.'));
 suffix=(char(space,length(space)));                  
cards;                                                
23436.000K                                            
    0.000K                                            
   50.688K                                            
 1340.160M                                            
  837.600K                                            
   47.190K                                            
 1187.640M                                            
   55.872K                                            
123A                                                  
;                                                     
proc print;                                           
run;                                                  

I received my desirable results:

OBS    SPACE             SIZE    SUFFIX
                                       
 1     23436.000K    23436.00      K   
 2     0.000K            0.00      K   
 3     50.688K          50.69      K   
 4     1340.160M      1340.16      M   
 5     837.600K        837.60      K   
 6     47.190K          47.19      K   
 7     1187.640M      1187.64      M   
 8     55.872K          55.87      K   
 9     123A            123.00      A  
Tom
Super User Tom
Super User

Your previous example is showing that you never read the last character of the string into the character variable. Why did you only read the first 11 bytes on the line? Why not just read more?  When writing a program with in-line data DO NOT INDENT the data. To make it clearer that you don't want to indent make sure to place the CARDS (or DATALINES) statement itself in column one.

 

Also to improve the logic have it only remove the last character if it is not a digit.  See if you can figure out how to modify the code to do that.

G_I_Jeff
Obsidian | Level 7

Tom,

I'm reading in a report dumped to a file to pull relevant data off of. This is to become a billing job, with space being the unit to be billed. The report is fixed length and the space field looks to be set at 11 bytes. The variable itself (I'm calling it space) is in a unique format that needs to be converted to gigabytes.

VOLSER DATA SET NAME                                   ADATE      BYTES  CAT
PRDA02 SYS2.NFCTEST.FDREPORT.TERSED                 2021.012    829.440K NO   .......
ZMF015 CHGMAN.W.XITCAW.#D913DD0.#0592618            2021.012     55.840K NO 
ZMF015 CHGMAN.W.NFA31.#D911493.#8C68F7C             2021.012     55.840K NO 
ZMF015 CHGMAN.W.XITCAW.#D90B107.#B41650E.OUTLIST    2021.012    839.940K NO 
ZMF015 CHGMAN.W.XITCAW.#D90C400.#91A2E30.OUTLIST    2021.012    839.940K NO 
ZMF007 CHGMAN.W.XITCAW.#D90C1F5.#0CC9442            2021.012     55.840K NO 
ZMF008 CHGMAN.W.XITCAW.#D90C447.#0A5E04A.OUTLIST    2021.012    839.940K NO 
ZMF008 CHGMAN.W.XITCAW.#D90C443.#D18977A.OUTLIST    2021.012    839.940K NO 
ZMF002 CHGMAN.W.XITCAW.#D90C3FA.#FC2A238.OUTLIST    2021.012    839.940K NO 
ZMF004 CHGMAN.W.XITCAW.#D90B0BB.#C4A5A4A.OUTLIST    2021.012    839.940K NO 
DEVA00 NFCD.TESTLOAD.MAINPPUB                       2021.012 286035.000K YES
DEVA03 NFCD.TESTLOAD.PARA.PDSE                      2021.012  15724.800K YES
DEVA04 NFCDABCO.CNTL.PAT                            2021.012   9883.680K YES
DEVA04 NFCD.TESTLOAD.ASDUAT                         2021.012 204228.990K YES
DEVA04 NFCD.TESTLOAD.ASDPARA                        2021.012 342097.860K YES
........
FINAL TOTALS --
BYTES------------263.060G

There are more fields to the right and a ton more records but this shows what I'm working with. If it were up to me, I would just write a quick Assembler job to handle this as I'm not proficient in SAS (obviously). I need to ignore the header/footer records. This data is not mine and I'm unfamiliar with it but this will feed invoicing so it is very sensitive. I'm trying to code a robust enough SAS job to handle any situation. Based on the limited amount of data I've received, it seems that the report converts the space to either kilobytes, megabytes or gigabytes. The space field needs to be converted to a common size, bytes in my case. The program must stop if any error is encountered with the conversion. Otherwise it will continue to invoice incorrectly.

Here is my attempt with your help from before:

DATA USER.FDREPORT;                                      
 INFILE INFILE;                                          
 INPUT @1  VOLSER   $6.                                  
       @8  DSNAME   $44.                                 
       @53 ARCDT    $8.                                  
       @62 SPACE    $11.                                 
       @74 CATALOG  $3.                                  
       @78 EXPDT    $8.                                  
       @87 RUNDT    $8.;                                 
 IF _N_ = 1 THEN DELETE;                                 
 IF _INFILE_ =: "FINAL TOTALS" THEN DELETE;              
 IF _INFILE_ =: "BYTES" THEN DELETE;                     
 SIZE=INPUTN(SPACE,CATS('COMMA',LENGTH(SPACE)-1,'.'));   
 SELECT (CHAR(SPACE,LENGTH(SPACE)));                     
  WHEN ('k','K') SIZE=SIZE*1024;                         
  WHEN ('m','M') SIZE=SIZE*1024**2;                      
  WHEN ('g','G') SIZE=SIZE*1024**3;                      
  OTHERWISE DO;                                          
    PUT 'SUFFIX NOT RECOGNIZED ' SPACE=$QUOTE.;          
    ABORT ABEND 055;                                     
  END;                                                   
 END;                                                    
 ARCDATE=INPUT(COMPRESS(ARCDT,'.'),JULIAN7.);            
 EXPDATE=INPUT(COMPRESS(EXPDT,'.'),JULIAN7.);            
 RUNDATE=INPUT(COMPRESS(RUNDT,'.'),JULIAN7.);            
 KEEP VOLSER DSNAME ARCDATE SIZE CATALOG EXPDATE RUNDATE;
RUN;                                                     

This is failing, I believe, on the first header record.

Tom
Super User Tom
Super User

If the header line only appears once you can skip the header line use FIRSTOBS=2 option on the INFILE statement.

INFILE INFILE firstobs=2;    

If the header line repeats (that is you are reading a print-out that repeats the header at the start of each page) then you will need to use a different method to identify the header line and skip it.

input ... 
if volser='VOLSER' then delete;

 

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 12 replies
  • 724 views
  • 0 likes
  • 4 in conversation