I am trying to use a script to verify the number prefix is in range. If not return false.
The keyUp event fires, but the self.props.text doesn’t update after the first event fires, until either a carriage return is enter, or focus has been lost. I also tried onKeyPress and onKeyDown. Is there a way to force self.props.text to update?
As a note it is a bit odd that Jython doesn’t appear to have a toFloat or parsefloat function that will parse a string and return the starting float value. Therefore I need to use something strange like the following.
float(str([i for i in (''.join((n if n in'0123456789.' else ' ') for n in self.props.text)).split()][0]))
I just found the deferUpdates check box, but you were quicker than me. Thank you!
I tried the float function, but it throws an error if there is an invalid character, where I want it to stop parsing and return the value. I could writeback to a prop parsing using toFloat then try and turn around to read that, but I am not sure that would be more readable or than the Jython lamba above. I will ponder that option tonight.
It's a strange script because this is a fairly strange requirement.
If someone enters 1234somethingWrong56, the only unambiguous thing to do is reject it as "not a float". You apparently want to take 1234 as the output of that input string, which is fine, and computers will let you do so, but someone else would be surprised by that - they really wanted 123456 as the output.
Your particular script is overcomplicated, also: float("".join(c if c in "0123456789." else " " for c in self.props.text).split()[0])
Or using regex if you prefer:
import re
float(re.search(r"[\d.]+", self.props.text).group())
######################################################
# ToFloat
######################################################
def ToFloat(str):
"""ToFloat
Convert a string to a floating point number with the default value of 0
Args:
str: string value that contains a number
Return:
float
The first floating point number. Default value 0
"""
str = str.strip()
point = str.find('.')
result = ''.join((n if n in '0123456789' else ' ') for n in str)
if point >= 0 :
result = result[:point] + '.' + result[point + 1:]
elif result.strip() == "":
result = "0"
return float(result.split()[0])
A few states that causes float() to throw exceptions.
0 prefix of numbers
alpha characters and symbols like space
multiple decimal points
empty strings
Edit:
I didn’t see your comment before I posted. But yes my original script was over complicated, I realized it when I went back to refactor it. The regex solution accounts for all cases except for empty string and multiple decimal points, but those are easy issues to resolve.
Sylistic judgement of CamelCase function name aside (), you really shouldn't name variables/parameters the same thing as Python builtins. It's "fine" in an isolated scope like this, but a bad practice because of the risk of shadowing something important and having it leak into another scope.
The biggest issue is that most people would assume camel case names are classes, not functions. Conventions exist for a reason. Same as if you saw a name in all caps, you would assume it was a constant
That is my C# background bleeding through. In C# we stylistically use Pascal Case for Class names, their methods and properties. We normally save camel case for variables. Stylistically I saw the project library as a static class and the function as a static method, verse a global function.
Since toFloat() is not available in Ignition Jython, I didn’t think there would be a fear in shadowing, especially in this Pascal Case version.
toFloat/ToFloat is fine - it's str as a parameter name that's the problem. That's the name of the Python builtin class.
toFloatmight cause confusion for someone down the line because there is a toFloatexpression language function, but someone who confuses scripts and expressions is bound to get confused by something
That is a good point! While I was trying to avoid string and stepped on the str landmine. I will changed it to something simple like value.
As for the method name, you make a strong argument. If I was perfectly mimicking the functionality that would be one thing. Since it doesn’t perfectly respond the same way in all cases as the toFloat, I could see how that would be confusing when I hand this off to another team to maintain. Probably more importantly if I add it library my team uses in other projects.
I could name it something like StoF mimicking my the old C++ days, but that sounds a bit brutalist. The more I think about it ParseFloat probably makes the most sense. Most of my developers are coming from C# background.