An Idea Exchange for SAS software and services

Comments
by Respected Advisor
on ‎01-30-2013 02:18 PM
Good afternoon! I haven't gone out yet. You?
by Super Contributor
on ‎01-30-2013 02:28 PM
I went out at noon and came back at 1:10. Just finished lunch. It was really warm outside.
by Respected Advisor
on ‎05-14-2014 01:36 PM

Why don't you just use the NLITERAL function when you use the validated string.

Actually I should have said YOU need to use DEQUOTE.  However that may not be correct for all users.  Bottom line all the functions are working as they should or so it would seem to me.

I think you confusing a valid ANY name with a name literal.  There is a difference between the name and its reference.

by Occasional Contributor btt7338
on ‎05-15-2014 06:21 PM

In validating a variable name passed to a macro, using NLITERAL would be altering the variable name.  NLITERAL is quite stupid.  Try this:

     %put %sysfunc(NLITERAL("Test Test Test"N));

and you will get this:

     '"Test Test Test"N'N

because the function doesn't bother to see whether the value is already a valid name literal or not...only whether it is a valid V7 name.

by Respected Advisor
on ‎05-15-2014 11:08 PM

22         %put %sysfunc(NLITERAL(%sysfunc(dequote("Test Test Test"N))));

"Test Test Test"N

If you look a what NLITERAL did you may think it dumb but it does exactly what you should expect.  The STRING is a valid ANYNAME and NLITERAL modified the string to be a valid NAME reference.

25         data _null_;

26            %sysfunc(NLITERAL("Test Test Test"N)) = "I'm doing what you asked";

27            %sysfunc(NLITERAL(%sysfunc(dequote("Test Test Test"N)))) = "I'm doing it again";

28            put (_all_)(/=);

29            run;

"Test Test Test"N=I'm doing what you asked

Test Test Test=I'm doing it again

by Occasional Contributor btt7338
on ‎05-16-2014 11:06 AM

That is all well and good but it does not help me with my original problem: Is the string contained in a macro parameter ready to be used as a variable name or not.  Either NVALID should definitively answer this question so that I can determine whether I need to call NLITERAL; or the NLITERAL function should not quote a valid name-literal.that is already enclosed.  I can take either.  But NVALID is the obvious place to fix it since I suspect NLITERAL calls NVALID internally.

If I want to validate that a name passed to a general macro is valid or not, my macro is not supposed to change the name-literal passed (in the example, "Test Test Test"N) to a different name-literal ('"Test Test Test"N'N).  These represent different variable names.  Obviously, I can use a macro to parse the name-literal.  But the function ought to do this much for me.

If I were really greedy, I'd ask NVALID to validate numbered and named range specifications, too, which I started to add as an idea as well.  SAS recognizes these specifications...it ought to have a function to validate them and NVALID would be a good place for it.  Right now, I'll settle for having the NVALID function do what most would expect it to do already.

In fact, I am at a bit of a loss to see what value the NVALID function has for name-literals, at all.  It seems obvious that its original purpose was validation of V7 names and the name-literals got tacked on.  Or, perhaps, its primary purpose validating names that were snooped from the DICTIONARY tables which would come as string variables rather than constants and so would not need be a problem.  This would be consistent with the way the function works with second parameter of ANY (that's why ANY is stupid about string lengths...it expects to see strings that are implicitly <=32 characters because they were pulled from the SASHELP.VCOLUMN dictionary table.).  But the way the function works with a second parameter of NLITERAL is goofed up because it does not validate an actual name-literal (which is intrinsically a constant) except to account for the fact that the quote-...-quote-N structure allows three extra bytes of length.  ANY is too stupid to do even that.

And NVALID is already buggy.  Puzzle over the results of the code below:

proc format ; value Logic    .="Missing" 0="False" 1="True" ; run ;

options validvarname=any ;

data Test ;

/*    Our test case is 'Test Test Test"--a very odd but legal name-literal        */

     String='''''Test Test Test"''n' ;

/*    Does SAS accept it as a valid variable name-literal?  Yes.                */

    '''Test Test Test"'n=1 ;

/*    Does NVALID with ANY parm accept it?  Yes.                            */

     ANYResult=NVALID(String,'ANY'     ) ; put "Result from NVALID(.,ANY) is " ANYResult Logic. ;

/*    Dose NVALID with NLITERAL parm accept it?  No.                        */

    NLITResult=NVALID(String,'NLITERAL') ; put "Result from NVALID(.,NLITERAL) is " NLITResult Logic. ;

    output ;

    run ;

proc print data=Test ; run ;

NVALID tells you that a name-literal string (which the code demonstrates is a valid SAS name-literal by creating a variable with it) is valid for ANY but not valid for NLITERAL!  And a blank parameter implies either V7 or ANY (NLITERAL does not enter into it, ever).  This leads me to believe that the behavior with the NLITERAL parameter is a bug...not a feature.  It was probably supposed to act the way I expect...to evaluate a name-literal as a constant.  But the programmers got their wires crossed and the feature is so seldom used that nobody has complained about it.  Of course, this bodes ill for me to get enough votes to change its behavior.  Maybe I should take it up with support as a bug fix.

by Respected Advisor
on ‎05-16-2014 11:15 AM

You are confusing the name with the reference.  That's what you can fix with DEQUOTE.

17         options validvarname=any ;

18         data Test ;

19         /*    Our test case is 'Test Test Test"--a very odd but legal name-literal        */

20             String='''Test Test Test"' ;

21         /*    Does SAS accept it as a valid variable name-literal?  Yes.                */

22             '''Test Test Test"'n=1 ;

23        

24         /*    Does NVALID with ANY parm accept it?  Yes.                            */

25              ANYResult =NVALID(String,'ANY'     ) ;          put "Result from NVALID(.,ANY) is " ANYResult Logic. ;

26              ANYResult2=NVALID(dequote(String),'ANY'     ) ; put "Result from NVALID(dequote(.),ANY) is " ANYResult2 Logic. ;

27        

28         /*    Dose NVALID with NLITERAL parm accept it?  No.                        */

29             NLITResult =NVALID(String,'NLITERAL') ;          put "Result from NVALID(.,NLITERAL) is " NLITResult Logic. ;

30             NLITResult2=NVALID(dequote(String),'NLITERAL') ; put "Result from NVALID(dequote(.),NLITERAL) is " NLITResult2 Logic.

30       !  ;

31             run ;

Result from NVALID(.,ANY) is True  

Result from NVALID(dequote(.),ANY) is True  

Result from NVALID(.,NLITERAL) is False 

Result from NVALID(dequote(.),NLITERAL) is True  

by Occasional Contributor btt7338
on ‎05-16-2014 11:56 AM

First, your call to dequote changed the name.  You can see this by adding this line to your code.

     NewString=dequote(String) ; put String / NewString ;

You changed the 'Test Test Test" to Test Test Test".  All dequote did was strip off the leading single-quote...but that is part of the name so the variable name changed.

Second, my original code (since edited) misspecified the name for my complete purpose though it still represents a bug.  The String should have been:

     String='''''Test Test Test"''n' ;

since this is the name-literal form of the name.  I want this form to be true with the NLITERAL parameter...the orignal string should fail to be valid.  By the way, put that string into your dequote function and smoke it.

No, I'm not confusing the name and the reference.  I'm saying that I want the function to validate the reference!  Not the name!  A name-literal is a reference and not a name.  So if something says it will validate a name-literal, I expect it to validate the string as a reference because that is what a name-literal is.  Except for trivially validating length (granted, not totally trivial for DBCS), what use is a validation for a name that can be anything?

But a name-literal has specific requirements that must be validated for a macro to use it as a name reference.  If a user passes string that is supposed to refer to a variable, I need to know whether my macro can use that string to refer to a variable or whether it should alert the caller that the name is not valid.  NVALID with the NLITERAL parameter is worthless for this.  In fact, I cannot see that the NLITERAL parameter does anything useful.  Again, I think the problem is that the SAS programmers were unclear what they were trying to add so they validated the name as though it were already in a dataset...and I can see no use to that.

Anyway, your comment did usefully clarify what I am seeking to anyone reading this so thank you.

by Respected Advisor
on ‎05-16-2014 01:22 PM

This (below) is what the documentation says and it makes sense to me.  Maybe it could be worded better but I understand it to say if string is used as a name, using the name literal syntax 'string'n, is it be valid.  That is all it does no assumptions are made about string that I can see.  When you use the string in your program you need to supply the proper syntax.  It ain't broke.

NLITERAL

determines that string is a valid SAS variable name if it is in the form of a SAS name literal ('name'N) or if it is a valid SAS variable name when VALIDVARNAME=V7.

See:V7 above in this same list.

by Occasional Contributor btt7338
on ‎05-16-2014 02:58 PM

Here is YOUR quote from the SAS Help on NVALID which you seem to think makes me stupid for not getting the "proper syntax" of an "ain't broken" function:

NLITERAL

determines that string is a valid SAS variable name if it is in the form of a SAS name literal ('name'N) or if it is a valid SAS variable name when VALIDVARNAME=V7.

And again, I point out that the NVALID function with the NLITERAL parameter declares strings valid that do not have the form 'name'N and are not valid SAS variable names when VALIDVARNAME=V7.  And here is some simple code that demonstrates that NVALID declares invalid strings (by your quote above) to be valid:

proc format ; value Logic.="Missing" 0="False" 1="True" ; run ;

data Test ;

/*--    This string does not have the form 'string'n and is not a valid variable name under V7    --*/

/*--    According to your quote from SAS Help, it should be FALSE.  Returns TRUE. Not broken?    --*/

    String='Not V7 & not a name-literal' ;

    Result=nvalid(String,'NLITERAL') ;

    put "NVALID(.,'NLITERAL') Returns " Result Logic. ;

    run ;

In the code above, I also demonstrated that NVALID declares strings invalid that are valid.  Do you get it now?

do SARCASM ;

I suppose in the strictest semantical parsing, the description of the NLITERAL parameter does not preclude that that SAS might determine that string is a valid SAS variable name for other reasons besides it not being a name-literal and not being a valid V7 name.  There is just an IF and not an ONLY-IF...I dunno, maybe because the name has an emoticon in it: ;-) or maybe it is a leap year or it was cloudy in Tokyo today or it generated a random number less than 5...so yeah, why not declare it a valid string for other undocumented reasons.  Nothing in the description precludes that.  Duh! What a dolt I am.

No reasons are given in the section you quote for why it might declare a string to be invalid, it can be whimsical on that, too.  The only firm promise that NVALID makes is that if I pass it a string that I know to be valid, it will confirm that for me.  It recalls that Looney Tunes episode where the guy is claiming his dog can talk:

"What sandpaper feel like?"     "Ruff!"

"What's on top of a house?"     "Roof"

"Who was the greatest baseball player?"      "Roof"

Maybe NVALID can occassionally say "DiMaggio".

Of course, you wouldn't but another reader might reply, "No, it broke its promise because it declared the valid string ''Test Test Test"''n to be invalid and it has the form of a name-literal in the earlier code from above and it said it would declare that valid. So it is broken."  To which SAS might respond with my favorite quote from SAS Help relating to name-literals (which you charitably did not quote):

CAUTION:

Throughout SAS, using the name literal syntax with variable names that exceed the 32-byte limit or have excessive embedded quotation marks might cause unexpected results.

The intent of the VALIDVARNAME=ANY system option is to enable compatibility with other DBMS variable (column) naming conventions, such as allowing embedded blanks and national characters.

HAH!  They are covered.  My example from above used embedded quotes!  We should expect the unexpected results as well as the Spanish Inquisition!!!   I must not confuse the poor SAS system with my underhanded attempts at logic...who do I think I am! Captain Kirk with SAS playing my M5 or my "Norman" or my NOMAD!  Go ahead, submit this code -- I DARE YOU:

data Test ;

     Name="'Jackson Roykirk'n" ;

     Result=NVALID(Name,'NLITERAL') ;

     run ;

Did your SAS meltdown, too!???

As I say, I probably should take this up with support since the function is clearly returning incorrect results (from the code above) and is clearly buggy (from the code I posted earlier where it cannot correctly parse quotes in the name).  I just wasn't sure that it didn't serve some useful purpose that I'm missing for some people.  This discussion has convinced me that it is just as useless an implementation as I thought and almost certainly not what was intended.  But there is a chance that somebody somewhere has used it and relied upon this behavior.  Hence, I suggested they implement the expected behavior and (as you so helpfully point out) documented behavior using alternate parameter values.

Apparently, you disagree and think it should declare every string to be valid...a sort of alternative representation for the constant, 1.  And since I am, apparently, the only person who was stupid enough to try to use the NLITERAL parameter with this P-O-S function, it seems unlikely that I'll get enough votes to get it changed into something useful and should stick to using my %NVALID macro which parses it properly.  To say nothing of the MVALID function which has the same problems!  Instead, I'll submit a IDEA request to SAS to have NVALID and MVALID validate parking stubs as well as names and maybe I can get some votes for that!

end SARCASM ;

Idea Statuses
Top Liked Authors