We are about to switch to a new forum software. Until then we have removed the registration on this forum.
I am getting an error when I attempt to use substring() as I iterate through an array. I want to extract an integer from a string of text. This works fine outside of an array:
String trainInfo = "E215\n17:30 - Howth to Bray (-3 mins late)\nArrived Dublin Connolly next stop Tara Street";
int start = trainInfo.indexOf("(" ) + 1; // STEP 1
int end = trainInfo.indexOf(" mins", start); // STEP 2
String status = trainInfo.substring(start, end); // STEP 3
int status_no = int(status); // STEP 4
println(status_no);
Whereas in my case I get an error at the point of the substring():
void requestData() {
for (int i = 0; i < children.length; i++) {
XML announcementElement = children[i].getChild("PublicMessage");
String announcement = announcementElement.getContent();
int start = announcement.indexOf("(" ) + 1; // STEP 1
int end = announcement.indexOf(" mins", start); // STEP 2
String status = announcement.substring(start, end); // STEP 3 ***error thrown at this point***
int status_no = int(status); // STEP 4
println(status_no);
}
}
[edit] Though not strictly related to Processing, I found a thread in the following forum that indicates that javascript does not permit substrings within arrays. I guess the same applies to Processing?: https://stackoverflow.com/questions/42429413/javascript-error-array-substring-is-not-a-function
The responder recommends to "slice and then remove the commas" or to use join(''). I have tried to to slice() and join(), based on Processing documentation but it's not working out.
Would anyone know of a way to get around this? Many thanks :)
Answers
I'm a bit confused -- you provide Processing(Java) example code, but then reference p5.js (JavaScript). Could you clarify which you are seeking a solution for? Or is it both?
Sorry, Jeremy. I meant that I just saw that answer there while googling the issue. I'm working in Processing only. I'll edit last the message now.
Which error do you get in which line please?
use
println( start, stop);
to find out if start and stop are good / correct valuesmaybe one entry in the xml is empty (or has no "(" or " mins")
use
if(.......)
then to skip the substring for that lineYes, both integers that go in to substring(), 'start' and 'end', print okay individually.
The error occurs on line 9 of the previous code posted:
The error that it throws is as so:
I'm sorry but I'm not sure what you mean by "use if then"?
What does the error say?
Well, when
(
is missing ormins
is missingstart
orstop
would be wrong / unusableOr is
announcement
empty maybe?This an example of the XML string I'm using: I'm iterating through many of these.
"E215\n17:30 - Howth to Bray (-3 mins late)\nArrived Dublin Connolly next stop Tara Street"
The issue could lie in the fact that "('minutes' mins late)" occurs in most but not all strings I'm iterating through. An example:
"P281\nMidleton to Cork\nExpected Departure 13:45"
All the following seem to println okay; "announcement", "start" and "end".
When I comment out the "substring()" line it runs okay but if I leave it uncommented I get this error:
I am trying to get around it by outputting a 0 value if "(" and " mins" don't occur within the string in which it is searching, like so:
That seems to throw a 0 every time however.
Yes indeed, when there is no ( or mins, start and stop have value-1 or so
Use
if
to check this to avoid errorYou can add some debugging lines:
And then see how to handle the errors, or spot a bug if there is any.
Kf
Thank you very much, Chrisir and Kfajer. With your help I got there in the end :)
:-bd
Kf
But now you need to do something with it
Eg calculate the average delays of trains for weekdays or for hours during a day
Or draw a graph in the for loop
Yup, already dong things. Drawn the train positions to a map to update when the XML feed updates and sending some messages over OSC to max for some complimentary sonification :)
@Newoso Not sure if you need line 77:
thread("requestData");
as you are managing the data retrieval in line 74.Kf
Thanks kfrajer, but if I uninclude it, none of my train marker get drawn to screen? Also I think I followed a Schiffman example on the timer section and I'm pretty sure this is how he did it. I'll double check.
You need to start your timer explicitly in setup. Notice you are requesting the xml data once in setup, so I guess your intentions is to update your client? If you decide to retrieve data from the server, make sure you don't flood it with too many requests aka send request as needed.
Kf
The XML feed I am accessing updates every minute. If I set my time to check every 30 secs, that should be fine shouldn't it?
Timer timer = new Timer(30000);
About the timer being started explicitly in setup, I'm not sure what you mean? Sorry.
Thanks again for your input.
Yes, 30 secs is not bad. I mean, if you know that resources are updated every 15 minutes, they you could check about every 5 minutes. My comments was more steering toward the case you were updating every second, which could get you block by your server. This would apply in cases where you have a limited number of requests.
What I mean is to start your timer in setup. Call
timer.start();
This made a difference when running your code. You might not needed as maybe the initial problem was that the xml called done in setup was taking a bit longer to return. In either case, your sml loading is being done only once in setup, not every so often as you stated in your prev post, or maybe I am missing something?
Kf
Sorry, I have so many scripts now I think I moved it to setup again without noticing while I was troubleshooting. D'oh!
I think I get when you mean now. On lines 21&22 I have moved timer.start(); and requestData() to setup so that all the values load on compiling and wait to be updated from the code within draw.
I have also commented out thread("requestData"); (line 59) as you siggested, as when I did a println I saw that it was throwing out lots of extra unwanted values.
Oh dear, but when I re-add the code to retrieve coordinates and draw the train locations I now get a null pointer exception on line 64:
map.addMarker(trainMarker);
.But if I delete
requestData();
from setup it runs fine (but the trains are obviously not drawn until the counter restarts).Then just make sure your obj is not null right before interacting with it:
if(trainMarker!=null){ ... }
Thxs for your newer code. It is more clear and shows better what you want to do. If you use osc, don't call those function right when requesting data. Instead, create another function to handle those cases. It keeps your code more clean and each function specific to its task.
Kf
Really, no need to thank me :-/ You're the one helping me out ;)
I wasn't sure where to put
if(trainMarker!=null){ ... }
, so I put it in line 26 before it requests data. The train positions still don't seem to print until the timer counts down.Also, with the OSC as a separate function (
void sendOSC(){
on line 105) and call it within the timer finished condition in draw(). It does not seem to iterate through the OSC messages.Basically, the overall visual end goal is to draw various vertical rectangles to the screen based on the late/early status of each train. For this I need to access the global variable 'onTimeStatus' (line 21). I cannot seem to access it in draw. I have also tried getting the requestData() (line 61) function to return an integer and retrieve it this way to no avail. Is there something basic I'm missing here?
I have left everything visible in the code below. It runs but behaves according to the above info. Thanks again.
This does not address all the questions. Check the code below where I have made some subtle changes all over the place.
Not clear what you mean. Where is this iteration taking place?
One additional note. When managing your data, you need to make sure you have valid data. Just because you call a function and you are expecting certain result doesn't mean your returned value has those values. The proper way to do this is to manage your returns. If your return has data, process it. Otherwise, skip or even better, provide an error or warning msg.
Kf
Regarding the bad explanation of OSC messages iteration, Sorry. To simplify, what I meant by:
Also, with the OSC as a separate function (void sendOSC(){ on line 105) and call it within the timer finished condition in draw(). It does not seem to iterate through the OSC messages.
I will just take 'latitude' as an example..
I rewrote some code to simplify. I don't understand why only the value of the first index of 'latitude' is being sent for all indices (line 19), when all discrete indices print out fine in the line before it. I hope this made sense.
Thank you very much for putting those hints in your previous code. I'll try to figure it out.
Ok, so I think my code above needs to be changed.
IsFinished()
should be:Right now your code doesn't work as the bus system must be down. This is not going to solve your problem: You need to choose another port number. Usually lower numbers are ports reserved for the system. You should use instead numbers above 5000 or 10000 as the chances they are taken is very low.
To test the oscP5, I use this modified version of the example provided here: http://www.sojamo.de/libraries/oscP5/examples/oscP5sendReceive/oscP5sendReceive.pde
You will see that I have attached 10 numbers and I can retrieve them in the other end. See the documentation for proper function calls. In your case:
Kf
Thanks kfrajer :) I'm sending OSC to Max.
I have used OSC with processing and max in the past. In case there were any crossed wires, my OSC setup was working fine, until I tried to set it up within it's own function, as you suggested.
I think I have an idea why only the first index of 'onTimeStatus' could be accessed outside of the requestData() function. I think the index values of 'onTimeStatus' needed to be stored in an array to enable them to be used outside of that function?
I am pretty sure this is not elegant coding, and you are probably going to vomit when you see this :-& .... but, after some hours this the only method that has allowed me to both draw those rectangles and send OSC messages using a discrete OSC function (line 95) that is called each time the timer counts down from within requestData() (line 82).
I am using a intArray list on line 17 to store the myTrainStatus values. Even though I'm inexperienced, I can tell that this is not the best way. But it works, for now. It is messy that I am having to use
myStatuses = statuses.get(i);
in two places; line 55 and 98.Here is the XML file I am using while that server is down (there are currently no trains running).
Not, it is not messy. You have some functions that need to access data. They access their data and their own convenient time. Can this be done more efficient? Maybe. However for this case you don't really need to go for optimization when you can get a more clear code. Nowadays computers are fast enough that nobody will notice in your case.
Glad to hear you figure your problem. All the best,
Kf
Thanks for your feedback, kfajer. I surely would not have gotten to this point without your tips and guidance. Much obliged :) Have a nice day.