String with variable length - "String index out of range"

Hi guys,

I am again struggling with one of my rules. :frowning:

Item “Tex_UDP_Incoming” receives it’s input via UDP.
It can contain values of variable length.

E.g. value "D0011 is possible, as well as "D001255
These values mean the following:

  • The second character (D) means the alarm is Disarmed.
  • The 3rd, 4th, 5th character (001) refer to the alarm partition;
  • The last part (1 or 255) refer to a user ID. Unfortunately, the length of this part is not fixed.

The code below works fine if the user ID consists out of three digits (e.g. 255). However, when user 1 is registered, I get the following message:

Rule 'Alarm interface via UDP': String index out of range: 8

The error message makes sense. But how do I make the rule below compatible with both user ID 1 and 255?

rule "Alarm interface via UDP"

when   
    Item  Tex_UDP_Incoming received update
then
    // We are only interested in the first 7 characters to process our items. The rest often contains NULL values that generate errors.
	val inStr = Tex_UDP_Incoming.state.toString.substring(0, 6)
	// When alarm is Disarmed (D) we register who disarmed it.
	if(inStr.startsWith("\"D0")) {
        postUpdate(Tex_Alarm_Status, "0")
		postUpdate(Tex_Alarm_Partition, inStr.substring(2, 5))
		postUpdate(Tex_Alarm_User, Tex_UDP_Incoming.state.toString.substring(5, 8))
    }
end

Thanks!
Dries

I’m not at my computer so can’t check, therefore the solution proposed may not exist. That being sais, often when a string is of variable length you could use a substring from # to stringLength or something similar. That way the length of the last bit is to the end however long it may be.

Hi @mikaelgu,

That makes sense. I tried to derive the length, by defined “Tex_UDP_Incoming.state.length”, but whenever I use “length” in my rule, I get:

2017-05-21 22:24:43.038 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'Alarm interface via UDP': An error occured during the script execution: The name '<XMemberFeatureCallImplCustom>.length' cannot be resolved to an item or type.

So I guess I do something wrong…

Seeing as you operating on the .toString of the state with substring(), isn’t that the thing you want the length of?

1 Like

Thanks, somehow I overlooked that, thanks!

	if(inStr.startsWith("\"D0")) {
        postUpdate(Tex_Alarm_Status, "0")
	postUpdate(Tex_Alarm_Partition, inStr.substring(2, 5))
	postUpdate(Tex_Alarm_User, Tex_UDP_Incoming.state.toString.substring(5, Tex_UDP_Incoming.state.toString.length))
    }

Hi,

Unfortunately I still have issues with the variable length of “Tex_UDP_Incoming”.

  • This string could have a length between 6 and 1024;
  • I am never interested in the information beyond 32. It is always filled with NULL values, which generates errors along the way (The argument ‘state’ must not be null or empty.)
  • So I could easily chop the last part off with “substring(0, 32)”;
  • However, in the cases where the received string is only 6 long. I would receive an “String index out of range: 32” error message;
  • Thanks to your help, I could use “substring(0, Tex_UDP_Incoming.state.toString.length)”
  • However, this code would imply I would get the NULL-part back in my variable.

So is there an operation I could apply that just takes the first 32 characters of a string, but also accepts less characters (no generation of string index out of range)?

Thanks,
Dries

You should check the length of the string first. That would be “Tex_UDP_Incoming.state.toString.length”.
Knowing the length of the string, you can prevent to call for substrings that are non-existing!

Ok, thanks. I’ll foresee an extra if-structure for this to check the length and use the right substring afterwards.