Hi,
Just wondering if it is possible to format a numeric based on values of specific digits in a PROC FORMAT?
For example, would it be possible to format these numbers based on the coloured digits only without a data step to split them out first? (for example, the thousands values, irrespective of what the other values are... is there a wildcard type approach?)
501210
701304
I'm aware how to do this in a data step but, having just concatenated the variables for efficiency, I don't want to split them back out for formatting.
EDIT: Adding context that I should have included in the first place!
The format of the variable could be either numeric or character - either works for my purposes, by character is easier. The use of the format would for grouping in a class in a PROC TABULATE. Definitely not in a PUT statement as I don't want to split the data back out.
For further context ... as an example, if my data has many variables in one row like: Value_at_8am [2 digits], Value_at_9am [2 digits], Value_at_10am [2 digits] ... and I concatenate them, can I then have a format that classifies based on the Value_at_9am in the new concatenated string irrespective of the value that come before or after it in the concatenated string?
So, Ideally, I have a concatenated string when any range 01-99 in the 3rd and 4th places could be formatted to "True":
Proc Format
Value wishful
**01** - **99** = "Value at 9am is True"
**00** = "Value at 9am is False"
****01-****99 = "Value at 10 am is True"
... etc.
cheers.
I might just be easiest to make your format from your data. So if your data looks like this:
data have;
input string $10. @1 number ;
cards;
501210
701304
600055
;
You could convert numeric variable NUMBER to the middle two digits by a formula like this:
data want;
set have;
want1 = int(mod(number,10**4)/10**2);
run;
So use that to make a CNTLIN dataset to define your name format. Let's call it V9AM.
proc sql ;
create table cntlin as
select distinct
'V9AM' as fmtname
, number as start
, int(mod(number,10**4)/10**2) as v9AM
, case when (calculated v9am = 0) then 'Value at 9am is False' else 'Value at 9am is True' end as label
from have
order by 1,2
;
quit;
proc format cntlin=cntlin; run;
Now you can use that format in your code:
proc print data=have ;
format number v9am. ;
run;
Obs string number 1 501210 Value at 9am is True 2 701304 Value at 9am is True 3 600055 Value at 9am is False
What type variable/format are you looking for here. Numeric or Character? Is your variable numeric or character?
Please explain what values you want be displayed by the format? For example show what displayed value you want for the stored values you showed.
How are you going to use this format? Just for printing the output? For grouping , like in a CLASS variable? For making a new variable with the PUT() function?
There may be other ways, but I know PROC FCMP will get your there:
DATA raw; INFILE DATALINES; INPUT myval $6.; DATALINES; 501210 701304 ; run; proc fcmp outlib=work.functions.fun; function mask(string $) $; return (substr(string,3,2)); endsub; run; options cmplib=work.functions; proc format; value $ mask (default=200) other=[mask()]; value $ masky '11' = 'Eleven' '12' = 'Twelve' '13' = 'Thirteen'; run; data results; set raw; formated = put(put(myval,$mask.),$masky.); run;
I realized you wanted a numeric format. Its a simple fix:
DATA raw; INFILE DATALINES; INPUT myval 8.; DATALINES; 501210 701304 ; run; proc fcmp outlib=work.functions.fun; function mask(num_in) $; return (substr(put(num_in,Z6.),3,2)); endsub; run; options cmplib=work.functions; proc format; value mask (default=200) other=[mask()]; value $ masky '11' = 'Eleven' '12' = 'Twelve' '13' = 'Thirteen'; run; data results; set raw; formated = put(put(myval,mask.),$masky.); run;
I might just be easiest to make your format from your data. So if your data looks like this:
data have;
input string $10. @1 number ;
cards;
501210
701304
600055
;
You could convert numeric variable NUMBER to the middle two digits by a formula like this:
data want;
set have;
want1 = int(mod(number,10**4)/10**2);
run;
So use that to make a CNTLIN dataset to define your name format. Let's call it V9AM.
proc sql ;
create table cntlin as
select distinct
'V9AM' as fmtname
, number as start
, int(mod(number,10**4)/10**2) as v9AM
, case when (calculated v9am = 0) then 'Value at 9am is False' else 'Value at 9am is True' end as label
from have
order by 1,2
;
quit;
proc format cntlin=cntlin; run;
Now you can use that format in your code:
proc print data=have ;
format number v9am. ;
run;
Obs string number 1 501210 Value at 9am is True 2 701304 Value at 9am is True 3 600055 Value at 9am is False
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.