<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Check numeric values in alphanumeric variables in SAS Procedures</title>
    <link>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/333687#M62846</link>
    <description>&lt;P&gt;/** Moderator's Edit **/&lt;/P&gt;
&lt;P&gt;This is a robust solution and includes links to macro code.&amp;nbsp; Other posters mention a variety of useful SAS functions and are worth a look.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/td-p/19247" target="_self"&gt;OPs&lt;/A&gt; solution is also good -- the input function&amp;nbsp;will try to convert the string to numeric and will return missing if it cannot.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Another simple solution is to&lt;STRONG&gt; add 0 to the character string&lt;/STRONG&gt; -- when using the '+' operator, SAS will automatically attempt to convert character&lt;BR /&gt;strings to numeric where possible. If SAS cannot do this, then the result returns a missing number because '+' cannot operate on character strings. This will not, however, recognize numbers such as '1,000'&lt;/P&gt;
&lt;P&gt;&lt;BR /&gt;&lt;A href="https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/19248#M3892" target="_self"&gt;DanielSantos&lt;/A&gt; gives several useful functions:&lt;BR /&gt;anyalpha - returns index of first alphabetic character&lt;BR /&gt;anydigit - returns index of first numeric character&lt;BR /&gt;notalpha - returns index of first NON alphabetic character (includes punctuation, etc)&lt;BR /&gt;notdigit - returns index of first NON numeric character (includes punctuation, etc)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;These functions don't give desired results when the string is something like '1.1.1', '1,000', '-500', etc.&lt;/P&gt;
&lt;P&gt;&lt;BR /&gt;PRXMATCH() (used as part of ScottBass's solution) is another way to accomplish this. Use the regular expression:&lt;BR /&gt;^ *[+-]?\d{1,3}(?:,\d{3})*\.?\d*$|^ *[+-]?\d*\.?\d*$|^ *[+-]?(?:\d+\.?\d*|\d*\.?\d+)[eE]-?\d+$&lt;/P&gt;
&lt;P&gt;This should capture positive/negative numbers, numbers with commas, and numbers in scientific notation using e or E.&lt;/P&gt;
&lt;P&gt;This site is a useful place to test regular expressions if you're curious: &lt;A href="https://regex101.com/r/xV4eL5/3" target="_blank"&gt;https://regex101.com/r/xV4eL5/3&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;/** end edit **/&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I needed to do this same thing today, and found this post.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;After mulling over this a bit, I've approached this problem a bit differently than the other replies. I'm replying to this old post in case someone searches for this in the future and prefers my approach.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;My approach is to use the INPUT function, best32. format, and ?? INPUT function modifiers, then check if the result is missing.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;We already know the input data is character (otherwise we wouldn't need this check!), so the input data is already in the data type (character) expected by the input function.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;With this approach, there are some additional checks I can do.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here is the code:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data test;
   length char $32;
   input char $char32.;
   num      = input(char,?? best32.);
   IsNum    = (not missing(num));
   IsNum2   = (not missing(num) or strip(char) in ('','.') or (.A le num le .Z) or (num eq ._));
   IsInt    = (not missing(num) and int(num) = num);
   IsFloat  = (abs(num - int(num)) gt 0);
   IsNotNeg = (num ge 0);
   IsPos    = (num gt 0);
   test=num-int(num);
   datalines;

.
._
.A
.Z
-1
0
1
1.1
 123456789012.123456789012
-123456789012.123456789012
 1234567890123.1234567890123
-1234567890123.1234567890123
 12345678901234.12345678901234
-12345678901234.12345678901234
 123456789012345.123456789012345
-123456789012345.123456789012345
 1234567890123456.1234567890123456
-1234567890123456.1234567890123456
 1.1
 -123
 -123.45
 --123.45
A
 B
123 456
~!@#$%^&amp;amp;*()_+=
;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;However, this will generate "Missing values were generated ..." messages in the SAS log. I like as clean a SAS log as possible. It's unfortunate that SAS doesn't support shortcircuit logic checking as done in many modern programming languages.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;So, here is Version 2; less terse code but with the same results:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data test;
   length char $32;
   input char $char32.;
   num = input(char,?? best32.);
   if (not missing(num)) then do;
      IsNum    = 1;
      IsNum2   = 1;
      IsInt    = (int(num) = num);
      IsFloat  = (abs(num - int(num)) gt 0);
      IsNotNeg = (num ge 0);
      IsPos    = (num gt 0);
      t1=num-int(num);
   end;
   else do;
      IsNum    = 0;
      IsNum2   = (strip(char) in ('','.') or (.A le num le .Z) or (num = ._));
      IsInt    = 0;
      IsFloat  = 0;
      IsNotNeg = 0;
      IsPos    = 0;
   end;
   datalines;

.
._
.A
.Z
-1
0
1
1.1
 123456789012.123456789012
-123456789012.123456789012
 1234567890123.1234567890123
-1234567890123.1234567890123
 12345678901234.12345678901234
-12345678901234.12345678901234
 123456789012345.123456789012345
-123456789012345.123456789012345
 1234567890123456.1234567890123456
-1234567890123456.1234567890123456
 1.1
 -123
 -123.45
 --123.45
A
 B
123 456
~!@#$%^&amp;amp;*()_+=
;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Comments:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;IsNum gives expected results, except for missing character input. Technically, "valid" character input which generates "expected" missing numeric data is in fact numeric input - a missing value is valid data in a SAS numeric column.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;IsNum2 compensates for this by checking the value of the character input for "valid" missing or special missing input, as opposed to invalid numeric input which converts to a missing value.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The check for IsInt and IsFloat collapses for large numeric data, as the precision is lost and the difference between int(num) - num becomes 0. If there is a better way to approach this precision issue please let me know (I investigated INTZ, CEIL/Z, and FLOOR/Z functions).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I also had to do this same thing with macro data, and wanted a "pure macro" solution, or function style macro (instead of running a data step). This is complicated by the fact that %sysfunc does not support the INPUT function, but only the INPUTN (and INPUTC) function instead, and the INPUTN function does not support the ?? modifier.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;(If a little birdie at SAS can explain the technical reasons why %sysfunc doesn't support the INPUT function, or why INPUTN doesn't support the ? and ?? modifiers, please email me privately).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here is my macro approach:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro IsNumM(char,type=NUM,missing=N);
   %let type=%upcase(&amp;amp;type);
   %let missing=%upcase(&amp;amp;missing);

   %* remove leading spaces ;
   %let char=&amp;amp;char;
   %* put CHAR=*&amp;amp;char*;  %* for debugging ;

   %* check if empty string or missing data ;
   %* if YES: ;
   %* if MISSING=N treat as not valid numeric data ;
   %* if MISSING=Y treat as valid numeric data ;
   %let rx = %sysfunc(prxparse(/^( *|\.[A-Z_]*)$/o));
   %let match = %sysfunc(prxmatch(&amp;amp;rx,%superq(char)));
   %syscall prxfree(rx);
   %if (&amp;amp;match eq 1) %then %do;
      %if (&amp;amp;missing) %then %let rtn=1; %else %let rtn=0;
&amp;amp;rtn
      %return;
   %end;

   %* use a Perl regex to test for numeric input ;
   %* the regex is "/^(-{0,1})(\d*)(\.{0,1})(\d*)$/o", which means: ;
   %* beginning of string (^): ;
   %* 0 or 1 minus signs: ;
   %* 0 or more digits: ;
   %* 0 or 1 periods: ;
   %* 0 or more digits: ;
   %* end of string ($) ;
   %* compile the regex once (o) ;
   %let rx = %sysfunc(prxparse(/^(-{0,1})(\d*)(\.{0,1})(\d*)$/o));
   %let match = %sysfunc(prxmatch(&amp;amp;rx,%superq(char)));
   %syscall prxfree(rx);

   %* if no match then not num ;
   %if (&amp;amp;match eq 0) %then %do;
0
      %return;
   %end;

   %* the Perl regex should be sufficient to cleanse the input to the inputn function ;   
   %* convert the value to num. if it is missing then not num ;
   %* note: this only supports options missing='.' and options missing=' ' ;
   %let num=%sysfunc(inputn(%superq(char),best32.),best32.);
   %let num=&amp;amp;num;
   %* put NUM =#&amp;amp;num#; %* for debugging ;
   %if (%superq(num) eq .) or (%superq(num) eq ) %then %do;
0
      %return;
   %end;

   %* it is probably a num :-) ;
   %if (&amp;amp;type eq NUM) %then %do;
1 
   %end;
   %else
   %if (&amp;amp;type eq INT) %then %do;
      %let int=%sysfunc(int(&amp;amp;num),32.);
      %* put INT =#&amp;amp;int#; %* for debugging ;
      %let rtn=%eval(&amp;amp;int eq &amp;amp;num);
&amp;amp;rtn
   %end;
   %else
   %if (&amp;amp;type eq NONNEG) %then %do;
      %let rtn=%sysevalf(&amp;amp;num ge 0);
&amp;amp;rtn
   %end;
   %else
   %if (&amp;amp;type eq POS) %then %do;
      %let rtn=%sysevalf(&amp;amp;num gt 0);
&amp;amp;rtn
   %end;
%mend;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Finally, I've macro-ized both approaches and have uploaded them to my GitHub repository:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="https://github.com/scottbass/SAS/blob/master/Macro/IsNum.sas" target="_blank" rel="noopener"&gt;https://github.com/scottbass/SAS/blob/master/Macro/IsNum.sas&lt;/A&gt;&lt;BR /&gt;&lt;A href="https://github.com/scottbass/SAS/blob/master/Macro/IsNumM.sas" target="_blank" rel="noopener"&gt;https://github.com/scottbass/SAS/blob/master/Macro/IsNumM.sas&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Hope this helps...&lt;/P&gt;</description>
    <pubDate>Thu, 11 Aug 2022 22:34:41 GMT</pubDate>
    <dc:creator>ScottBass</dc:creator>
    <dc:date>2022-08-11T22:34:41Z</dc:date>
    <item>
      <title>Check numeric values in alphanumeric variables</title>
      <link>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/19247#M3891</link>
      <description>Hi to all,&lt;BR /&gt;
in T-SQL there is a simple function (called isnumeric()) which checks if the value inside a column is numeric or not.&lt;BR /&gt;
I couldn't find anything similar in SAS functions (to be used in datasteps/proc sql)...the first (and at the moment, working) solution I've found is to check with the value returned from an input:&lt;BR /&gt;
&lt;BR /&gt;
proc sql;&lt;BR /&gt;
    select *&lt;BR /&gt;
    from work.test a&lt;BR /&gt;
    where input(a.charValue,best.) = .;&lt;BR /&gt;
quit;&lt;BR /&gt;
&lt;BR /&gt;
I wanted to know...is there a better way? Is the method I've adopted correct?&lt;BR /&gt;
Thanks&lt;BR /&gt;
&lt;BR /&gt;
Daniele

Message was edited by: Daniele Tiles</description>
      <pubDate>Wed, 15 Apr 2009 16:02:56 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/19247#M3891</guid>
      <dc:creator>DanieleTiles</dc:creator>
      <dc:date>2009-04-15T16:02:56Z</dc:date>
    </item>
    <item>
      <title>Re: Check numeric values in alphanumeric variables</title>
      <link>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/19248#M3892</link>
      <description>Hello Daniele&lt;BR /&gt;
&lt;BR /&gt;
There is a "neater" way of doing that.&lt;BR /&gt;
There is actually a couple of functions for checking the contents of a char variable for alpha or num chars. &lt;BR /&gt;
&lt;BR /&gt;
Check:&lt;BR /&gt;
ANYALPHA: &lt;A href="http://support.sas.com/documentation/cdl/en/lrdict/61724/HTML/default/a002194060.htm" target="_blank"&gt;http://support.sas.com/documentation/cdl/en/lrdict/61724/HTML/default/a002194060.htm&lt;/A&gt;&lt;BR /&gt;
ANYDIGIT: &lt;A href="http://support.sas.com/documentation/cdl/en/lrdict/61724/HTML/default/a002194193.htm" target="_blank"&gt;http://support.sas.com/documentation/cdl/en/lrdict/61724/HTML/default/a002194193.htm&lt;/A&gt;&lt;BR /&gt;
NOTALPHA: &lt;A href="http://support.sas.com/documentation/cdl/en/lrdict/61724/HTML/default/a002194058.htm" target="_blank"&gt;http://support.sas.com/documentation/cdl/en/lrdict/61724/HTML/default/a002194058.htm&lt;/A&gt;&lt;BR /&gt;
NOTDIGIT: &lt;A href="http://support.sas.com/documentation/cdl/en/lrdict/61724/HTML/default/a002194195.htm" target="_blank"&gt;http://support.sas.com/documentation/cdl/en/lrdict/61724/HTML/default/a002194195.htm&lt;/A&gt;&lt;BR /&gt;
&lt;BR /&gt;
Greetings from Portugal.&lt;BR /&gt;
&lt;BR /&gt;
Daniel Santos at &lt;A href="http://www.cgd.pt" target="_blank"&gt;www.cgd.pt&lt;/A&gt;</description>
      <pubDate>Wed, 15 Apr 2009 16:10:11 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/19248#M3892</guid>
      <dc:creator>DanielSantos</dc:creator>
      <dc:date>2009-04-15T16:10:11Z</dc:date>
    </item>
    <item>
      <title>Re: Check numeric values in alphanumeric variables</title>
      <link>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/19249#M3893</link>
      <description>Hi Daniel,&lt;BR /&gt;
thanks for the suggestion! However, I've tested the method that seemed to fit best my issues (NOTDIGIT)...but I've found two remarks (one solved, the other one...):&lt;BR /&gt;
-- NOTDIGIT has to consider also blanks, so it has to be called always as NOTDIGIT(TRIM(LEFT(&amp;lt;&amp;lt;STRING&amp;gt;&amp;gt;)))...but that's ok&lt;BR /&gt;
-- The NOTDIGIT might be useful for recognizing integers, but not float/double (for example, if I have to check that a SALES field has got not numeric values....the dot isn't (rightly) recognized as digit).</description>
      <pubDate>Wed, 15 Apr 2009 17:55:51 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/19249#M3893</guid>
      <dc:creator>DanieleTiles</dc:creator>
      <dc:date>2009-04-15T17:55:51Z</dc:date>
    </item>
    <item>
      <title>Re: Check numeric values in alphanumeric variables</title>
      <link>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/19250#M3894</link>
      <description>Hello Danielle.&lt;BR /&gt;
&lt;BR /&gt;
OK, if your dealing with blanks and floats try the ANYALPHA function instead the NOTDIGIT.&lt;BR /&gt;
&lt;BR /&gt;
data _null_;&lt;BR /&gt;
if anyalpha('    2    ') then put 'ALPHA'; else put 'DIGIT';&lt;BR /&gt;
if anyalpha('2.2') then put 'ALPHA'; else put 'DIGIT';&lt;BR /&gt;
if anyalpha('    2.2    ') then put 'ALPHA'; else put 'DIGIT';&lt;BR /&gt;
&lt;BR /&gt;
/* caution, this will fail for digits with more than one . */&lt;BR /&gt;
if anyalpha('2.2.2') then put 'ALPHA'; else put 'DIGIT';&lt;BR /&gt;
run;&lt;BR /&gt;
&lt;BR /&gt;
Greetings from Portugal.&lt;BR /&gt;
&lt;BR /&gt;
Daniel Santos at &lt;A href="http://www.cgd.pt" target="_blank"&gt;www.cgd.pt&lt;/A&gt;</description>
      <pubDate>Thu, 16 Apr 2009 08:46:35 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/19250#M3894</guid>
      <dc:creator>DanielSantos</dc:creator>
      <dc:date>2009-04-16T08:46:35Z</dc:date>
    </item>
    <item>
      <title>Re: Check numeric values in alphanumeric variables</title>
      <link>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/277606#M58771</link>
      <description>&lt;P&gt;if you want to check that all char of your string are numeric in a simple and fast way: you can use &lt;A href="http://support.sas.com/documentation/cdl/en/lefunctionsref/67960/HTML/default/viewer.htm#p0aesccozrvg19n1bg83z1jb9nid.htm" target="_blank"&gt;Verify Function(variable, &amp;lt;list of character to find&amp;gt;),&lt;/A&gt; &lt;EM&gt;that returns the position of the first character in a string that is not in any of several other strings.&lt;/EM&gt; If you list all number(see example) function give to you 0 that means the values in string are all numeric..&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data _null_;
length string_to_verify $12.;

    string_to_verify='1234567';
    check               = notdigit(string_to_verify);
    &lt;STRONG&gt;check2             = verify(trim(left(string_to_verify)),'0123456789')&lt;/STRONG&gt;;
        put string_to_verify= check= check2=;

    string_to_verify ='12345678';
    check                = notdigit(string_to_verify);
    check2              = verify(trim(left(string_to_verify)),'0123456789');
        put string_to_verify= check= check2=;

    string_to_verify ='1234567 9';
    check                = notdigit(string_to_verify);
    check2              = verify(trim(left(string_to_verify)),'0123456789');
        put string_to_verify= check= check2=;

    string_to_verify ='123';
    check                = notdigit(string_to_verify);
    check2              = verify(trim(left(string_to_verify)),'0123456789');
        put string_to_verify= check= check2=;

    string_to_verify ='A123';
    check                = notdigit(string_to_verify);
    check2              = verify(trim(left(string_to_verify)),'0123456789');
        put string_to_verify= check= check2=;

    string_to_verify ='A1B23';
    check                = notdigit(string_to_verify);
    check2              = verify(trim(left(string_to_verify)),'0123456789');
        put string_to_verify= check= check2=;

    string_to_verify ='1B23';
    check                = notdigit(string_to_verify);
    check2              = verify(trim(left(string_to_verify)),'0123456789');
        put string_to_verify= check= check2=;

    string_to_verify ='AAA3';
    check                = notdigit(string_to_verify);
    check2              = verify(trim(left(string_to_verify)),'0123456789');
        put string_to_verify= check= check2=;

    string_to_verify ='123C';
    check                = notdigit(string_to_verify);
    check2              = verify(trim(left(string_to_verify)),'0123456789');
        put string_to_verify= check= check2=;
run;&lt;BR /&gt;&lt;BR /&gt;* LOG: ------------------------------------------------------------------;&lt;BR /&gt;&lt;BR /&gt;string_to_verify=1234567   check=8 check2=0&lt;BR /&gt;string_to_verify=12345678  check=9 check2=0&lt;BR /&gt;string_to_verify=1234567 9 check=8 check2=8 /*blank char is not numeric!*/&lt;BR /&gt;string_to_verify=123       check=4 check2=0&lt;BR /&gt;string_to_verify=A123      check=1 check2=1&lt;BR /&gt;string_to_verify=A1B23     check=1 check2=1&lt;BR /&gt;string_to_verify=1B23      check=2 check2=2&lt;BR /&gt;string_to_verify=AAA3      check=1 check2=1&lt;BR /&gt;string_to_verify=123C      check=4 check2=4&lt;BR /&gt;&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;&lt;A href="http://www.lexjansen.com/pharmasug/2005/CodersCorner/cc01.pdf" target="_self"&gt;here&lt;/A&gt; there's a beautyfull pdf and &lt;A href="http://www2.sas.com/proceedings/sugi30/233-30.pdf" target="_self"&gt;there&lt;/A&gt;'s another on 'Charachter function' with a lot of example (ex. anydigit, etc..).&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;bye&lt;/P&gt;</description>
      <pubDate>Wed, 15 Jun 2016 16:22:04 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/277606#M58771</guid>
      <dc:creator>MC1985</dc:creator>
      <dc:date>2016-06-15T16:22:04Z</dc:date>
    </item>
    <item>
      <title>Re: Check numeric values in alphanumeric variables</title>
      <link>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/333687#M62846</link>
      <description>&lt;P&gt;/** Moderator's Edit **/&lt;/P&gt;
&lt;P&gt;This is a robust solution and includes links to macro code.&amp;nbsp; Other posters mention a variety of useful SAS functions and are worth a look.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/td-p/19247" target="_self"&gt;OPs&lt;/A&gt; solution is also good -- the input function&amp;nbsp;will try to convert the string to numeric and will return missing if it cannot.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Another simple solution is to&lt;STRONG&gt; add 0 to the character string&lt;/STRONG&gt; -- when using the '+' operator, SAS will automatically attempt to convert character&lt;BR /&gt;strings to numeric where possible. If SAS cannot do this, then the result returns a missing number because '+' cannot operate on character strings. This will not, however, recognize numbers such as '1,000'&lt;/P&gt;
&lt;P&gt;&lt;BR /&gt;&lt;A href="https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/19248#M3892" target="_self"&gt;DanielSantos&lt;/A&gt; gives several useful functions:&lt;BR /&gt;anyalpha - returns index of first alphabetic character&lt;BR /&gt;anydigit - returns index of first numeric character&lt;BR /&gt;notalpha - returns index of first NON alphabetic character (includes punctuation, etc)&lt;BR /&gt;notdigit - returns index of first NON numeric character (includes punctuation, etc)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;These functions don't give desired results when the string is something like '1.1.1', '1,000', '-500', etc.&lt;/P&gt;
&lt;P&gt;&lt;BR /&gt;PRXMATCH() (used as part of ScottBass's solution) is another way to accomplish this. Use the regular expression:&lt;BR /&gt;^ *[+-]?\d{1,3}(?:,\d{3})*\.?\d*$|^ *[+-]?\d*\.?\d*$|^ *[+-]?(?:\d+\.?\d*|\d*\.?\d+)[eE]-?\d+$&lt;/P&gt;
&lt;P&gt;This should capture positive/negative numbers, numbers with commas, and numbers in scientific notation using e or E.&lt;/P&gt;
&lt;P&gt;This site is a useful place to test regular expressions if you're curious: &lt;A href="https://regex101.com/r/xV4eL5/3" target="_blank"&gt;https://regex101.com/r/xV4eL5/3&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;/** end edit **/&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I needed to do this same thing today, and found this post.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;After mulling over this a bit, I've approached this problem a bit differently than the other replies. I'm replying to this old post in case someone searches for this in the future and prefers my approach.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;My approach is to use the INPUT function, best32. format, and ?? INPUT function modifiers, then check if the result is missing.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;We already know the input data is character (otherwise we wouldn't need this check!), so the input data is already in the data type (character) expected by the input function.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;With this approach, there are some additional checks I can do.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here is the code:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data test;
   length char $32;
   input char $char32.;
   num      = input(char,?? best32.);
   IsNum    = (not missing(num));
   IsNum2   = (not missing(num) or strip(char) in ('','.') or (.A le num le .Z) or (num eq ._));
   IsInt    = (not missing(num) and int(num) = num);
   IsFloat  = (abs(num - int(num)) gt 0);
   IsNotNeg = (num ge 0);
   IsPos    = (num gt 0);
   test=num-int(num);
   datalines;

.
._
.A
.Z
-1
0
1
1.1
 123456789012.123456789012
-123456789012.123456789012
 1234567890123.1234567890123
-1234567890123.1234567890123
 12345678901234.12345678901234
-12345678901234.12345678901234
 123456789012345.123456789012345
-123456789012345.123456789012345
 1234567890123456.1234567890123456
-1234567890123456.1234567890123456
 1.1
 -123
 -123.45
 --123.45
A
 B
123 456
~!@#$%^&amp;amp;*()_+=
;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;However, this will generate "Missing values were generated ..." messages in the SAS log. I like as clean a SAS log as possible. It's unfortunate that SAS doesn't support shortcircuit logic checking as done in many modern programming languages.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;So, here is Version 2; less terse code but with the same results:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data test;
   length char $32;
   input char $char32.;
   num = input(char,?? best32.);
   if (not missing(num)) then do;
      IsNum    = 1;
      IsNum2   = 1;
      IsInt    = (int(num) = num);
      IsFloat  = (abs(num - int(num)) gt 0);
      IsNotNeg = (num ge 0);
      IsPos    = (num gt 0);
      t1=num-int(num);
   end;
   else do;
      IsNum    = 0;
      IsNum2   = (strip(char) in ('','.') or (.A le num le .Z) or (num = ._));
      IsInt    = 0;
      IsFloat  = 0;
      IsNotNeg = 0;
      IsPos    = 0;
   end;
   datalines;

.
._
.A
.Z
-1
0
1
1.1
 123456789012.123456789012
-123456789012.123456789012
 1234567890123.1234567890123
-1234567890123.1234567890123
 12345678901234.12345678901234
-12345678901234.12345678901234
 123456789012345.123456789012345
-123456789012345.123456789012345
 1234567890123456.1234567890123456
-1234567890123456.1234567890123456
 1.1
 -123
 -123.45
 --123.45
A
 B
123 456
~!@#$%^&amp;amp;*()_+=
;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Comments:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;IsNum gives expected results, except for missing character input. Technically, "valid" character input which generates "expected" missing numeric data is in fact numeric input - a missing value is valid data in a SAS numeric column.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;IsNum2 compensates for this by checking the value of the character input for "valid" missing or special missing input, as opposed to invalid numeric input which converts to a missing value.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The check for IsInt and IsFloat collapses for large numeric data, as the precision is lost and the difference between int(num) - num becomes 0. If there is a better way to approach this precision issue please let me know (I investigated INTZ, CEIL/Z, and FLOOR/Z functions).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I also had to do this same thing with macro data, and wanted a "pure macro" solution, or function style macro (instead of running a data step). This is complicated by the fact that %sysfunc does not support the INPUT function, but only the INPUTN (and INPUTC) function instead, and the INPUTN function does not support the ?? modifier.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;(If a little birdie at SAS can explain the technical reasons why %sysfunc doesn't support the INPUT function, or why INPUTN doesn't support the ? and ?? modifiers, please email me privately).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here is my macro approach:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro IsNumM(char,type=NUM,missing=N);
   %let type=%upcase(&amp;amp;type);
   %let missing=%upcase(&amp;amp;missing);

   %* remove leading spaces ;
   %let char=&amp;amp;char;
   %* put CHAR=*&amp;amp;char*;  %* for debugging ;

   %* check if empty string or missing data ;
   %* if YES: ;
   %* if MISSING=N treat as not valid numeric data ;
   %* if MISSING=Y treat as valid numeric data ;
   %let rx = %sysfunc(prxparse(/^( *|\.[A-Z_]*)$/o));
   %let match = %sysfunc(prxmatch(&amp;amp;rx,%superq(char)));
   %syscall prxfree(rx);
   %if (&amp;amp;match eq 1) %then %do;
      %if (&amp;amp;missing) %then %let rtn=1; %else %let rtn=0;
&amp;amp;rtn
      %return;
   %end;

   %* use a Perl regex to test for numeric input ;
   %* the regex is "/^(-{0,1})(\d*)(\.{0,1})(\d*)$/o", which means: ;
   %* beginning of string (^): ;
   %* 0 or 1 minus signs: ;
   %* 0 or more digits: ;
   %* 0 or 1 periods: ;
   %* 0 or more digits: ;
   %* end of string ($) ;
   %* compile the regex once (o) ;
   %let rx = %sysfunc(prxparse(/^(-{0,1})(\d*)(\.{0,1})(\d*)$/o));
   %let match = %sysfunc(prxmatch(&amp;amp;rx,%superq(char)));
   %syscall prxfree(rx);

   %* if no match then not num ;
   %if (&amp;amp;match eq 0) %then %do;
0
      %return;
   %end;

   %* the Perl regex should be sufficient to cleanse the input to the inputn function ;   
   %* convert the value to num. if it is missing then not num ;
   %* note: this only supports options missing='.' and options missing=' ' ;
   %let num=%sysfunc(inputn(%superq(char),best32.),best32.);
   %let num=&amp;amp;num;
   %* put NUM =#&amp;amp;num#; %* for debugging ;
   %if (%superq(num) eq .) or (%superq(num) eq ) %then %do;
0
      %return;
   %end;

   %* it is probably a num :-) ;
   %if (&amp;amp;type eq NUM) %then %do;
1 
   %end;
   %else
   %if (&amp;amp;type eq INT) %then %do;
      %let int=%sysfunc(int(&amp;amp;num),32.);
      %* put INT =#&amp;amp;int#; %* for debugging ;
      %let rtn=%eval(&amp;amp;int eq &amp;amp;num);
&amp;amp;rtn
   %end;
   %else
   %if (&amp;amp;type eq NONNEG) %then %do;
      %let rtn=%sysevalf(&amp;amp;num ge 0);
&amp;amp;rtn
   %end;
   %else
   %if (&amp;amp;type eq POS) %then %do;
      %let rtn=%sysevalf(&amp;amp;num gt 0);
&amp;amp;rtn
   %end;
%mend;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Finally, I've macro-ized both approaches and have uploaded them to my GitHub repository:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="https://github.com/scottbass/SAS/blob/master/Macro/IsNum.sas" target="_blank" rel="noopener"&gt;https://github.com/scottbass/SAS/blob/master/Macro/IsNum.sas&lt;/A&gt;&lt;BR /&gt;&lt;A href="https://github.com/scottbass/SAS/blob/master/Macro/IsNumM.sas" target="_blank" rel="noopener"&gt;https://github.com/scottbass/SAS/blob/master/Macro/IsNumM.sas&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Hope this helps...&lt;/P&gt;</description>
      <pubDate>Thu, 11 Aug 2022 22:34:41 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/333687#M62846</guid>
      <dc:creator>ScottBass</dc:creator>
      <dc:date>2022-08-11T22:34:41Z</dc:date>
    </item>
    <item>
      <title>Re: Check numeric values in alphanumeric variables</title>
      <link>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/333688#M62847</link>
      <description>&lt;P&gt;Note this approved solution does not cater for valid negative numeric data.&lt;/P&gt;</description>
      <pubDate>Fri, 17 Feb 2017 07:04:39 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Procedures/Check-numeric-values-in-alphanumeric-variables/m-p/333688#M62847</guid>
      <dc:creator>ScottBass</dc:creator>
      <dc:date>2017-02-17T07:04:39Z</dc:date>
    </item>
  </channel>
</rss>

