Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

RFC - isInt() / isHex()

Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
05-01-2008 04:28
[Edit: Added Comments to try and explain the flow as the code is somewhat criptic, and added a basic test for C99 Hex Float notation]
[Edit: Adjusted to compile in both LSL, LSLEditor and MONO, also added Exponent test to Int, Float and Numeric]

A group of little utility functions that others may find useful.
I know it could be more readable but I was after performance over legibility.

Each function may be used alone, but are grouped here for ease of posting.

Any one care to comment if there is a more efficient method of achieving this, or if the exceptions are a showstopper? The only exceptions I have found in my testing are 12. And .12 are not seen as numeric, however 12.0 and 0.12 are correctly identified as numeric and as float, I see this as mathematically correct even though LSL recognises the format without 0.
CODE

integer isInt(string val)
//is the string val a valid integer?
{
integer exp;//if an exponent is present we need to record its position
//remove white space, convert any Alpha charecters to lowercase and see if the first charecter is "-"
//if it is then remove it
if(!llSubStringIndex(val = llStringTrim(llToLower(val),STRING_TRIM),"-"))val = llGetSubString(val,1,-1);
//does the value have an exponent?
if(~(exp = llSubStringIndex(val,"e")))
//if it has and the exponent is negative, in all likelyhood, this value will be a float so abort
{if("-" == llGetSubString(val,exp + 1, exp + 1))return FALSE;
//otherwise remove the exponent from the string
else val = llGetSubString(val,0,exp - 1);}
//all special charecters should now be gone so remove the valid numerals, if anything is left then this is not a valid integer.
return !llStringLength(llDumpList2String(llParseString2List(llDumpList2String(llParseString2List(val,["0","1","2","3","4"],[]),""),["5","6","7","8","9"],[]),""));
}

integer isFloat(string val)
//is the string val a valid Float?
{
integer point; integer exp;//if an exponent or a point are present we need to record the positions
//remove white space, convert any Alpha charecters to lowercase and see if the value has an exponent
if(~(exp = llSubStringIndex(val = llStringTrim(llToLower(val),STRING_TRIM),"e")))
//determine if the exponent is negative then remove the exponent from the string
//both variables are used out of context to avoid the overhead of decclaring a 3rd variable.
{point = llSubStringIndex(llGetSubString(val,exp + 1,exp + 1),"-");val = llGetSubString(val,0,exp - 1);exp = point;}
//look for the decimal point and if present remove it from the string
if(~(point = llSubStringIndex(val,".")))val = llGetSubString(val,0, point - 1) + llGetSubString(val, point + 1, -1);
//if there was no decimal point and the exponent, if any, was not negative this is not a float so abort
else if(!(~exp))return FALSE;
//finaly, if this is a negative number, remove the "-"
if(!llSubStringIndex(val,"-"))val = llGetSubString(val,1,-1);
//all special charecters should now be gone so remove the valid numerals, if anything is left then this is not a valid Float.
return !llStringLength(llDumpList2String(llParseString2List(llDumpList2String(llParseString2List(val,["0","1","2","3","4"],[]),""),["5","6","7","8","9"],[]),""));
}

integer isHex(string val)
{
//is the string val a valid Hex Number?
integer point;
//remove white space, convert any Alpha charecters to lowercase and see if the first charecter is "-"
//if it is then remove it
if(!llSubStringIndex(llStringTrim(llToLower(val),STRING_TRIM),"-"))val = llGetSubString(val,1,-1);
//LSL recognises "0x" as the Hex prefix, if it is not present this is not hex so abort, otherwise remove it.
if(~llSubStringIndex(val,"0x"))val = llGetSubString(val,2,-1);else return FALSE;
//look for the decimal point and if present remove it from the string
if(~(point = llSubStringIndex(val,".")))val = llGetSubString(val,0, point - 1) + llGetSubString(val, point + 1, -1);
//LSL (float) typecast supports C99 hex floats so look for the "p" and remove it
if(~(point = llSubStringIndex(val,"p")))val = llGetSubString(val,0,point - 1);
//all special charecters should now be gone so remove the valid numerals, if anything is left then this is not a valid Hex Number.
return !llStringLength(llDumpList2String(llParseString2List(llDumpList2String(llParseString2List(val,["0","1","2","3","4","5","6","7"],[]),""),["8","9","a","b","c","d","e","f"],[]),""));
}

integer isNumeric(string val)
{
//is val in a format that LSL will corectly interprate as a number?
integer point; list mask = ["8","9"];//our mask has 2 forms Decimal and Hex, we will default it to decimal
//remove white space, convert any Alpha charecters to lowercase look for the decimal point and if present remove it from the string
if(~(point = llSubStringIndex(val = llStringTrim(llToLower(val),STRING_TRIM),".")))val = llGetSubString(val,0,point - 1)+llGetSubString(val,point + 1, -1);
//look for an exponant, as we dont care if it is possitive or negative in this case just remove it
if(~(point = llSubStringIndex(val,"e")))val = llGetSubString(val,0,point - 1);
//and do the same thing for a possible Hex Flat exponent of "p"
if(~(point = llSubStringIndex(val,"p")))val = llGetSubString(val,0,point - 1);
//if this is a negative number, remove the "-"
if(!llSubStringIndex(val,"-"))val = llGetSubString(val,1,-1);
//LSL recognises "0x" as the Hex prefix, if it is present remove it and use the Hex mask for the final test.
if(!llSubStringIndex(val,"0x")){val = llGetSubString(val,2,-1); mask = ["8","9","a","b","c","d","e","f"];}
//all special charecters should now be gone so remove the valid numerals, if anything is left then this is not a valid Number.
return !llStringLength(llDumpList2String(llParseString2List(llDumpList2String(llParseString2List(val,["0","1","2","3","4","5","6","7"],[]),""),mask,[]),""));
}

default
{
state_entry()
{
llListen(0,"","","");
}
listen(integer channel, string name, key id, string message)
{
llOwnerSay("Numeric "+(string)isNumeric(message));
llOwnerSay("Integer "+(string)isInt(message));
llOwnerSay("Hex "+(string)isHex(message));
llOwnerSay("Float "+(string)isFloat(message));
llOwnerSay("result int = "+(string)((integer)message)+" float = "+(string)((float)message));
llOwnerSay((string)llGetFreeMemory());
}
}


The test code should be self-explanatory.
Thanks in advance for any feedback.
Dora Gustafson
Registered User
Join date: 13 Mar 2007
Posts: 779
05-01-2008 04:37
well, what is the purpose? ( I am not too clever, sory )
_____________________
From Studio Dora
Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
05-01-2008 04:47
The main use is if you need to be sure that a valid integer is being used for a calculation.
For instance 4 / (integer)"two" will give a script error but 4 / (integer)"2" will = 2.

It is mainly used in situations where you are passing numeric values as strings in chat or LinkMessage functions.

Another situation may be if you receive a float value and are performing integer math, you may wish to issue an error message rather than truncate the float and compound rounding errors.

Having now posted all 4 versions I think the potental use becomes clearer.
Meade Paravane
Hedgehog
Join date: 21 Nov 2006
Posts: 4,845
05-01-2008 08:30
For isInt, I think it would be cheaper to let the sim try to cast it..

Something like this maybe:
CODE

integer isInt (string str)
{
return (string)((integer)str) == str;
}


edit: does it really give you a script error if you try to cast a non-numeric value to a number? I would have sworn that it just returned a 0 if the cast choked.
_____________________
Tired of shouting clubs and lucky chairs? Vote for llParcelSay!!!
- Go here: http://jira.secondlife.com/browse/SVC-1224
- If you see "if you were logged in.." on the left, click it and log in
- Click the "Vote for it" link on the left
Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
05-01-2008 08:41
From: Meade Paravane
For isInt, I think it would be cheaper to let the sim try to cast it..

Something like this maybe:
CODE

integer isInt (string str)
{
return (string)((integer)str) == str;
}


edit: does it really give you a script error if you try to cast a non-numeric value to a number? I would have sworn that it just returned a 0 if the cast choked.


In the example I gave it would geneate a division by zero error, and the problem with a simple type cast is that "abc" will return 0 but "1abc" will return 1.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
05-01-2008 09:00
I hate to be the bearer of bad news... but it doesn't compile.
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Meade Paravane
Hedgehog
Join date: 21 Nov 2006
Posts: 4,845
05-01-2008 09:12
From: Very Keynes
In the example I gave it would geneate a division by zero error, and the problem with a simple type cast is that "abc" will return 0 but "1abc" will return 1.

That's why you compare it back to the original string - '1abc' doesn't equal '1'.
edit: but I guess 01234 doesn't equal 1234.. Never mind.

From: Strife Onizuka
I hate to be the bearer of bad news... but it doesn't compile.

Mine? I'm not too, too surprised as I'm not somewhere where I can login right now. I think the idea is sound, though.
_____________________
Tired of shouting clubs and lucky chairs? Vote for llParcelSay!!!
- Go here: http://jira.secondlife.com/browse/SVC-1224
- If you see "if you were logged in.." on the left, click it and log in
- Click the "Vote for it" link on the left
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
05-01-2008 09:19
My left prim eyeball for a good regular expression library. PLEASE vote: http://jira.secondlife.com/browse/SVC-790
Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
05-01-2008 10:45
From: Strife Onizuka
I hate to be the bearer of bad news... but it doesn't compile.


Thanks Strife, I was running it in LSLEditor as I can't get online at the moment. I will test it in world later and post the edit back here.
OK, done and tested in both environments.
[Edit: Adjusted to compile in both LSL and LSLEditor]
Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
05-01-2008 14:07
From: Hewee Zetkin
My left prim eyeball for a good regular expression library. PLEASE vote: http://jira.secondlife.com/browse/SVC-790

I would give my male alts xcite bits for it :) Voted.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
05-01-2008 21:43
Your float parser doesn't handle explicitly positive exponents or hex floats.
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
05-02-2008 01:05
From: Strife Onizuka
Your float parser doesn't handle explicitly positive exponents or hex floats.

Could you be a bit more specific, I have had no problems with positive exponents, both 1.2e3 and 1.2e+3 are identified as numeric and as floats.
As for hex floats, I am from an electronics background, not a programming one, so to me a hex value is a hex value, neither float nor integer, and is identified as such. How the programmer interprets the content of that value is application specific. Having said that I would love to know what a hex float is, having never used that I am aware off it is an opportunity for me to learn something new. :)
Johan Laurasia
Fully Rezzed
Join date: 31 Oct 2006
Posts: 1,394
05-02-2008 01:30
Might as well add this to the mix...

CODE

integer query;

string evenOrOdd (integer foo)
{
if (foo & 1)
{
return "odd";
}
else
{
return "even";
}
}

default
{
state_entry()
{
query = 4;
string result = evenOrOdd (query);
llSay (0, (string)query + " is " + result);
}
}
Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
05-02-2008 02:36
Strife, I did some digging but the only real reference I could find to hex float's is your LibraryFloat2Hex entry in the wiki and the link to C99 hex floats, a somewhat cryptic reference by RedHat. I have implemented a trap for stings such as "0x1.fp3" as referenced in the above, and as a result it returns valid for both isNumeric and isHex.
Will that be sufficient or do you think I need to take it further, and if so how?
Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
05-02-2008 02:53
Sorry Johan, I couldn't resist :)

CODE

integer query;

integer isOdd(integer foo){return(foo & 1);}

default
{
state_entry()
{
query = 4;
if(isOdd(query))llSay (0, (string)query + " is Odd");
else llSay (0, (string)query + " is Even");
}
}
Johan Laurasia
Fully Rezzed
Join date: 31 Oct 2006
Posts: 1,394
05-02-2008 12:06
From: Very Keynes
Sorry Johan, I couldn't resist :)

CODE

integer query;

integer isOdd(integer foo){return(foo & 1);}

default
{
state_entry()
{
query = 4;
if(isOdd(query))llSay (0, (string)query + " is Odd");
else llSay (0, (string)query + " is Even");
}
}


Yeah, more than one way to skin a cat... that's pretty compact too :)