Snippet stringType

Discussion in 'Systems and Snippets' started by Darthfett, Jan 4, 2010.

  1. Darthfett

    Darthfett Super Mod

    Ratings:
    +614 / 0 / -0
    stringType
    Created by Darthfett

    Description:
    A small collection of functions that can be used to determine a string's type, such as if it is numerical, a metacharacter, etc.

    Requirements:
    N/A

    The rest of the documentation can be found in the system code, below:

    JASS:
    library stringType
    /*
    __________________________________________________________________________________
    
            stringType library, created by Darthfett - version 1.2
            http://www.thehelper.net/forums/showthread.php?t=143592
            
                                    Requirements
                                    
    -vJass compiler (such as JASSHelper)
        -If you remove the library and multi-line comment(s), you can make this JASS compatable.
    
                                    Documentation
                                    
    -All functions are standalone.  Feel free to copy an individual function.
    
    -Credit for this library is not necessary.  Feel free to use it in your map.
    If you feel obligated to credit me, I won't object.  I only ask that you do 
    not simply copy and paste the library as your own.
    
                                        API
    
    function IsInt takes string s returns boolean
        returns whether a string is a numeric integer.
        (Not necessarily within integer bounds)
        
    function IsReal takes string s returns boolean
        returns whether a string a numeric real.
        (Not necessarily within real bounds)
        
    function IsLetter takes string s returns boolean
        returns whether the specified character is a letter (a-z,A-Z).
        
    function IsLetters takes string s returns boolean
        returns whether the specified string contains only letters (a-z,A-Z).
        
    function IsMeta takes string s returns boolean
        returns whether the specified character is a metacharacter (!@#$%^...)
        
    function IsMetas takes string s returns boolean
        returns whether the specified string contains only metacharacters (!@#$%...)
    __________________________________________________________________________________
    */
    
    function IsInt takes string s returns boolean
        local integer i = 0
        local integer j
        local string c
        local integer len
        local integer sublen
        if s == "" or s == null or s == "-" or s == "+" then
            return false
        endif
        if I2S(S2I(s)) == s then
            return true
        endif
        set len = StringLength(s)
        loop
            set sublen = IMinBJ(i+8,len)
            exitwhen i == len
            set c = SubString(s,i,sublen)
            if I2S(S2I(c)) != c then
                set j = sublen
                loop
                    exitwhen j == i
                    set c = SubString(s,j-1,j)
                    if I2S(S2I(c)) != c then
                        if (c == "+" or c == "-") and j == 1 then
                            //pass
                        else
                            return false
                        endif
                    endif
                    set j = j - 1
                endloop
            endif
            set i = sublen
        endloop
        return true
    endfunction
    
    function IsReal takes string s returns boolean
        local integer i = 0
        local integer j
        local integer k = 0
        local string c
        local integer len
        local integer sublen
        if s == "" or s == null or s == "-" or s == "+" then
            return false
        endif
        if R2S(S2R(s)) == s then
            return true
        endif
        set len = StringLength(s)
        loop
            set sublen = IMinBJ(i+8,len)
            exitwhen i == len
            set c = SubString(s,i,sublen)
            if I2S(S2I(c)) != c then
                if R2S(S2R(c)) == c then
                    set k = k + 1
                    if k > 1 then
                        return false
                    endif
                else
                    set j = sublen
                    loop
                        exitwhen j == i
                        set c = SubString(s,j-1,j)
                        if I2S(S2I(c)) != c then
                            if c == "." then
                                set k = k + 1
                                if k > 1 then
                                    return false
                                endif
                            elseif (c == "+" or c == "-") and j == 1 then
                                //pass
                            else
                                return false
                            endif
                        endif
                        set j = j - 1
                    endloop
                endif
            endif
            set i = sublen
        endloop
        return true
    endfunction
    
    function IsLetter takes string s returns boolean
        return StringCase(s,true) != StringCase(s,false) and StringLength(s) == 1
    endfunction
    
    function IsLetters takes string s returns boolean
        local integer i = 0
        local string str
        loop
            set str = SubString(s, i, i + 1)
            exitwhen str == ""
            if StringCase(s,true) == StringCase(s,false) then
                return false
            endif
            set i = i + 1
        endloop
        return true
    endfunction
    
    function IsMeta takes string s returns boolean
        return I2S(S2I(s)) != s and StringCase(s,true) == StringCase(s,false) and StringLength(s) == 1
    endfunction
    
    function IsMetas takes string s returns boolean
        local integer i = 0
        local string str
        if StringCase(s,true) != StringCase(s,false) then
            return false
        endif
        loop
            set str = SubString(s, i, i + 1)
            exitwhen str == ""
            if I2S(S2I(str)) == str then
                return false
            endif
            set i = i + 1
        endloop
        return true
    endfunction
    
    endlibrary
     
  2. Steel

    Steel Software Engineer

    Ratings:
    +109 / 0 / -0
    These operations are a misnomer, you cannot determine if a string is a type, you can only determine if a character is a type.
     
  3. Darthfett

    Darthfett Super Mod

    Ratings:
    +614 / 0 / -0
    Why do you say that?

    Except for the int/numerical functions, it checks the string character by character. If the string is contained entirely of metacharacters, it isMeta. If it is contained entirely of alphabetical characters, it isAlpha.
     
  4. TriggerHappy

    TriggerHappy ...

    Ratings:
    +341 / 0 / -0
    JASS:
    function IsNumeric takes string str returns boolean
        if (str == "0") then
            return true
        endif
        return S2I(str) != 0 
    endfunction
     
  5. Azlier

    Azlier Old World Ghost

    Ratings:
    +461 / 0 / -0
    @TriggerHappy
    JASS:
    if IsNumeric("000") then
        call BJDebugMsg("All's good.")
    else
        call BJDebugMsg("Hold on...")
    endif
     
  6. TriggerHappy

    TriggerHappy ...

    Ratings:
    +341 / 0 / -0
    Erm, fine.
    At the very least he should check S2I(str) != 0 before doing all those calculations.
     
  7. Azlier

    Azlier Old World Ghost

    Ratings:
    +461 / 0 / -0
    The optimal method would be to check I2S(S2I(s)) == s. If not, then check if the string is composed entirely of zeroes.
     
  8. tooltiperror

    tooltiperror Super Moderator Staff Member

    Ratings:
    +233 / 0 / -0
    Str == vJass shortage of 'string'?
     
  9. Azlier

    Azlier Old World Ghost

    Ratings:
    +461 / 0 / -0
    What?
     
  10. Weep

    Weep Godspeed to the sound of the pounding

    Ratings:
    +400 / 0 / -0
    No, it's the name he gave a variable: function IsNumeric takes string str returns boolean
     
  11. Executor

    Executor I see you

    Ratings:
    +57 / 0 / -0
    What about "IsReal"?
     
  12. Darthfett

    Darthfett Super Mod

    Ratings:
    +614 / 0 / -0
    Update Version 1.1

    Good point, mine would also have problems with that.

    That would make no sense, as S2I("!%GJAWasdfj") will also return 0.

    What if the string is 0175971? If I then compare 1 and 0, the function would return false.

    Good point.

    I've updated the library with a new IsReal function, and I've merged the IsInt and IsNumeric functions so that the problem with 0s is fixed.
     
  13. Azlier

    Azlier Old World Ghost

    Ratings:
    +461 / 0 / -0
    Last I checked 0# is an 8-bit number. Is 065343 even valid?
     
  14. Deaod

    Deaod Member

    Ratings:
    +6 / 0 / -0
    Last i checked, a leading 0 indicates base 8 numbers only in code. I dont think S2I recognizes that.

    Yes, 065343 is a valid base 8 number. 0175971 is not.
     
  15. Lyerae

    Lyerae I keep popping up on this site from time to time.

    Ratings:
    +105 / 0 / -0
    I believe if it starts with an 0, it's octal, right?
    I'm not exactly sure how JASS processes integers though.
     
  16. Darthfett

    Darthfett Super Mod

    Ratings:
    +614 / 0 / -0
    Well anyways, this should correctly process all numbers now, whether or not the game uses S2I to turn 010 into 10 or 8, it should correctly determine that it is an integer.
     
  17. Ghan

    Ghan Administrator - Servers are fun Staff Member

    Ratings:
    +773 / 0 / -0
    Approved.
     
  18. Troll-Brain

    Troll-Brain You can change this now in User CP.

    Ratings:
    +85 / 0 / -0
    Because i'm doing a string calculator i need these kind of functions, however i've found that your IsInt function fails with valid syntaxes such as "+66","002","-0".

    So i've made my own, i think that is well commented but if you don't understand something you can still ask me :)

    JASS:
    function IsInt takes string whichString returns boolean
        local integer i
        local string s
        
        if I2S(S2I(whichString)) == whichString then // it's definitely an integer
            return true
        elseif StringLength(whichString) <= 1 then // there is no way it's a valid integer
            return false
        endif
        set s = SubStringBJ(whichString,1,1) 
        if not(s == "+" or s == "0" or s == "-") then // invalid integer because it's the only reason why a valid integer could be different when converted with S2I(I2S) , s == "-" is needed because of "-0"
            return false
        endif
        // now cheking for 0
        set i = 1
        loop
        set i = i+1
        set s = SubStringBJ(whichString,i,i) 
        // check the string left to right while we found a "0" character
        exitwhen s == "" or s == null
            if S2I(s) == 0 then // it could be a 0, and since we take only one character it can't be < 0 
                if s != "0" then // it's not a 0, so it's an invalid character
                    return false // invalid integr
                endif
            // fatally s > 0 here, time to check the left part of the string    
            elseif not(S2I(SubStringBJ(whichString,i,StringLength(whichString))) == IAbsBJ(S2I(whichString))) then
                return false // invalid integer
            else
                exitwhen true // this check is valid but we need to check the right part of the string now
            endif
        endloop
        
        // checking the right part of the string (if it's not already done)
        loop
        set i = i+1
        set s = SubStringBJ(whichString,i,i)
        exitwhen s == "" or s == null
            if S2I(s) == 0 and s != "0" then   // invalid integer
                return false
            endif
        endloop
        
        return true
    endfunction


    Notes :

    You can inline SubStringBJ if you don't want lame comments about BJ usage.
    I simply like the BJ because it makes more sense for me, or in other words i make less mistakes when i need to cut a string.
    It is not like a such function would be used each 0.001 s anyway ...
    And wc3mapoptimizer is your friend, more, he even doesn't inline constant handles (private joke) !

    It's kinda the same for "IAbsBJ".

    EDIT :
    It will also fail with IsReal for explicit negatives and positives reals, like "+5.1234" "-9.1234"
    And finally IsMeta and IsLetter should care about the StringLength which strictly must be == 1.
     
    • Like Like x 1
  19. Darthfett

    Darthfett Super Mod

    Ratings:
    +614 / 0 / -0
    Thanks for pointing out a few bugs in the IsInt function, I missed them when I optimized the inner loop. This was causing problems with integers longer than 8, and integers that started with 0's.

    I've fixed the bug, and also updated the system to support the use of signed ints/reals ('+' and '-', because '+5' has the same logical value as '5' which is returned by S2I('+5')).

    I've been able to retain most of the original optimizations I made, as I simply made the functions cut off any leading '+' or '-', and the IsInt function will no longer SubString slice from any area larger than the length, using the IMinBJ function (What's this, a useful BJ function?!).

    Troll-Brain, thanks for creating your own, but while this is true, I believe that in a submitted system, I should go out of the way to make it as lightweight as can be. I have a nice optimization for longer strings (it will check the string in slices of 8 chars before resorting to single characters (and only checks each of those 8 chars, going back to slices of 8 if that slice checks out okay)).

    I thought about doing this, but when using < 8 character length strings, it does avoid the bloat around using the loop for the IsMetas and IsLetters functions.

    Anyone else have any opinions about this? Technically if it's > 1 character, it isn't a character.
     
  20. Troll-Brain

    Troll-Brain You can change this now in User CP.

    Ratings:
    +85 / 0 / -0
    Totally by accident I've found a new bug now, "--X" returns true when X > 0, same with "+-X".

    JASS:
    if SubString(s,0,1) == "-" or SubString(s,0,1) == "+" then
       set s = SubString(s,1,StringLength(s))
    endif

    You don't need to redefine the string, just to skip the first character of it (i==1).
    The reason of the bug is i suppose the order of the if I2S(S2I(s)) == s should be done the first, or after the "null", or "" check (didn't tested)

    Sure, but i think the difference between using SubStringBJ and SubString is totally negligible comparing the use of SubString by itself though.
    I mean cutting the string would be much more slower than this difference between the BJ and the native.

    I think that 'sublen' is unneeded, i mean you can simply use 'i' instead.
    Also i don't like this idea of cutting string, why not simply the whole string ?

    If you consider a string which have a length > 1 , that makes IsLetter as a no sense because of the existent of IsLetters
     

Share This Page