diff --git a/base/mp_aligndecimal.sas b/base/mp_aligndecimal.sas
new file mode 100644
index 0000000..35ef8e2
--- /dev/null
+++ b/base/mp_aligndecimal.sas
@@ -0,0 +1,94 @@
+/**
+ @file
+ @brief Apply leading blanks to align numbers vertically in a char variable
+ @details This is particularly useful when storing numbers (as character) that
+ need to be sorted.
+
+ It works by splitting the number left and right of the decimal place, and
+ aligning it accordingly. A temporary variable is created as part of this
+ process (which is automatically dropped)
+
+ The macro can be used only in data step, eg as follows:
+
+ data _null_;
+ length myvar $50;
+ do i=1 to 1000 by 50;
+ if mod(i,2)=0 then j=ranuni(0)*i*100;
+ else j=i*100;
+
+ %mp_aligndecimal(myvar,width=7)
+
+ leading_spaces=length(myvar)-length(cats(myvar));
+ putlog +leading_spaces myvar;
+ end;
+ run;
+
+ The generated code will look something like this:
+
+ length aligndp4e49996 $7;
+ if index(myvar,'.') then do;
+ aligndp4e49996=cats(scan(myvar,1,'.'));
+ aligndp4e49996=right(aligndp4e49996);
+ myvar=aligndp4e49996!!'.'!!cats(scan(myvar,2,'.'));
+ end;
+ else do;
+ aligndp4e49996=myvar;
+ aligndp4e49996=right(aligndp4e49996);
+ myvar=aligndp4e49996;
+ end;
+
+ Results (myvar variable):
+
+ 0.7683559324
+ 122.8232796
+ 99419.50552
+ 42938.5143414
+ 763.3799189
+ 15170.606073
+ 15083.285773
+ 85443.198707
+ 2022999.2251
+ 12038.658867
+ 1350582.6734
+ 52777.258221
+ 11723.347628
+ 33101.268376
+ 6181622.8603
+ 7390614.0669
+ 73384.537893
+ 1788362.1016
+ 2774586.2219
+ 7998580.8415
+
+
+ @param var The (data step) variable to create
+ @param width= (8) The number of characters BEFORE the decimal point
+
+
SAS Macros
+ @li mf_getuniquename.sas
+
+ Related Programs
+ @li mp_aligndecimal.test.sas
+
+ @version 9.2
+ @author Allan Bowe
+**/
+
+%macro mp_aligndecimal(var,width=8);
+
+ %local tmpvar;
+ %let tmpvar=%mf_getuniquename(prefix=aligndp);
+ length &tmpvar $&width;
+ if index(&var,'.') then do;
+ &tmpvar=cats(scan(&var,1,'.'));
+ &tmpvar=right(&tmpvar);
+ &var=&tmpvar!!'.'!!cats(scan(&var,2,'.'));
+ end;
+ else do;
+ &tmpvar=cats(&var);
+ &tmpvar=right(&tmpvar);
+ &var=&tmpvar;
+ end;
+ drop &tmpvar;
+
+%mend mp_aligndecimal;
diff --git a/base/mp_assertcolvals.sas b/base/mp_assertcolvals.sas
index 7176782..129c39d 100644
--- a/base/mp_assertcolvals.sas
+++ b/base/mp_assertcolvals.sas
@@ -42,6 +42,7 @@
@param [in] test= (ALLVALS) The test to apply. Valid values are:
@li ALLVALS - Test is a PASS if ALL values have a match in checkvals
@li ANYVAL - Test is a PASS if at least 1 value has a match in checkvals
+ @li NOVAL - Test is a PASS if there are NO matches in checkvals
@param [out] outds= (work.test_results) The output dataset to contain the
results. If it does not exist, it will be created, with the following format:
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
@@ -97,7 +98,7 @@
%let test=%upcase(&test);
- %if &test ne ALLVALS and &test ne ANYVAL %then %do;
+ %if &test ne ALLVALS and &test ne ANYVAL and &test ne NOVAL %then %do;
%mp_abort(
mac=&sysmacroname,
msg=%str(Invalid test - &test)
@@ -153,6 +154,9 @@
%else %if &test=ALLVALS %then %do;
if &result=0 then test_result='PASS';
%end;
+ %else %if &test=NOVAL %then %do;
+ if &result=&orig then test_result='PASS';
+ %end;
%else %do;
test_comments="&sysmacroname: Unsatisfied test condition - &test";
%end;
diff --git a/tests/base/mp_aligndecimal.test.sas b/tests/base/mp_aligndecimal.test.sas
new file mode 100644
index 0000000..e8e4b06
--- /dev/null
+++ b/tests/base/mp_aligndecimal.test.sas
@@ -0,0 +1,44 @@
+/**
+ @file
+ @brief Testing mp_aligndecimal macro
+ @details Creates an aligned variable and checks the number of leading blanks
+
+ SAS Macros
+ @li mp_aligndecimal.sas
+ @li mp_assertcolvals.sas
+
+**/
+
+
+
+/* target values */
+data work.checkds;
+ do checkval='1234.56',' 123.45',' 123.4 ',' 1.2 ',' 0';
+ output;
+ end;
+run;
+
+/* raw values */
+data work.rawds;
+ set work.checkds;
+ tgtvar=cats(checkval);
+ drop checkval;
+run;
+
+%mp_assertcolvals(work.rawds.tgtvar,
+ checkvals=work.checkds.checkval,
+ desc=No values match (ready to align),
+ test=NOVAL
+)
+
+/* aligned values */
+data work.finalds;
+ set work.rawds;
+ %mp_aligndecimal(tgtvar,width=4)
+run;
+
+%mp_assertcolvals(work.finalds.tgtvar,
+ checkvals=work.checkds.checkval,
+ desc=All values match (aligned),
+ test=ALLVALS
+)