Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I have to read a text document with data formatted as follows: (a couple of examples)

07 M W F 1400 1450 C 2004
M W F 0900 1030 EN 2036
06 M T R 1300 1350 EN 1003
17 T R 0900 1015 EN 1052

The problem I'm having is, once splitting up these strings with .split(" ", -1), I get a different number of tokens for many of them, and the position of the difference varies in the first two "sections".

The first part of the string is supposed to represent a scheduling code. It's optional, as can be seen by it being missing in the second line. The second area depicts which days of the week this schedule applies to. It could be anywhere from one to five days, but in these examples there are only 2 or 3. Then the rest are pretty much static: Start time, end time, building code and room number.

What I need to do is construct multiple objects for this schedule based on this info (one object for each day), and I'm not sure how to proceed. How can I tell, when iterating over the array of tokens, what each token represents? I thought about using a switch statement, but that would only work for the days, as there are 5 of them.

The following is the code I (tentatively) plan to use for this object.

public class TimeSlot {

  private Day day;
  private int startTime;    // # of minutes after midnight
  private int endTime;
  private Room room;
  private String slot;

  /**
   * Default constructor. Create an instance of TimeSlot.
   * @param day   day of the week
   * @param start start time of lecture represented as minutes after midnight
   * @param end   end time of lecture represented as minutes after midnight
   * @param room  room the class takes place in
   */
  public TimeSlot(String slot, Day day, int start, int end, Room room) {
    this.slot = slot;
    this.day = day;
    this.startTime = start;
    this.endTime = end;
    this.room = room;
  }
}

enum Day {
  MONDAY,
  TUESDAY,
  WEDNESDAY,
  THURSDAY,
  FRIDAY,
  SATURDAY,
  SUNDAY;
}

public class Room {

  private String buildingCode;
  private String roomNumber;

  public Room(String building, String room) {
    this.buildingCode = building;
    this.roomNumber = room;
  }

  public String buildingCode() {
    return buildingCode;
  }

  public String roomNumber() {
    return roomNumber;
  }

}
share|improve this question

4 Answers 4

up vote 4 down vote accepted

As much as people sometimes complain about regular expressions, this is a perfect scenario for using them. I'm not familiar with the syntax for Java myself (but here's a reference), but I can tell you that you're going to want the pattern:

(\d+ )?([MTWRF] )+(\d+) (\d+) (\w+) (\d+)

You can test it out here.

Step by step, this means:

  • (\d+ )? - If they exist, capture any number of digits followed by a space.
  • ([MTWRF] )+ - Capture a letter from the set MTWRF followed by a space, as many times as it happens (but at least once).
    • If you want to enforce the 1-5 rule, replace the + with {1,5}, so it becomes ([MTWRF] ){1,5}.
    • If you want to include Saturday and Sunday, add S and U inside the [] block (order doesn't matter), so it would become ([UMTWRFS] )+.
  • (\d+) - Capture a series of digits. If you want to enforce four digits, replace the + with {4} so it becomes (\d{4}), or simply put in four \d characters to make (\d\d\d\d).
  • (\d+) - Capture another series of digits. See above for modifications.
  • (\w+) - Capture a series of letters
  • (\d+) - Capture a last series of digits. See above for modifications.

You then can access each capture - if the first one doesn't match, it should be empty. If the second one matches multiple letters, you can just get those by splitting on spaces. All other ones don't even have stray spaces for you to worry about.

share|improve this answer
1  
If you want to make it complete, the MTWRF system typically uses S for Saturday and U for Sunday... just in case there's a class on the weekend. –  MichaelT Jan 16 at 17:11
    
@MichaelT - Good suggested. Added them in. –  Bobson Jan 16 at 17:14
    
I initially tried to do this with regex but was having problems capturing the optional integer out front. For the case where there was none, it was leaving that group blank, and chopping off the first day in the next group... so I was getting days "W F" instead of "M W F" for the second line. This works though, with a slight change to the regex code: I used "(\\d+ )?([MTWRF ]+) (\\d+) (\\d+) (\\w+) (\\d+)". Note: The + for the days is inside the group, not outside. With it outside, I was getting only one day –  agent154 Jan 16 at 17:51
    
@agent154 - Interesting. When I tested it, it matched just fine, but I didn't check the groups. My guess is that it was incrementing the capture count for each day, which just brought you back to the original problem. Good fix, though, and I'm glad it worked! –  Bobson Jan 16 at 18:05

First step is to shoot the person who chose to collect the data that way: variable numbers of fields without identifiers is pretty tedious. Also, day of the week is ridiculous for a room scheduling app, unless you're scheduling it for months at a time (with some kind of default end date?). This would be a non-issue if you stored dates.

In this case however, you can probably just parse through the arguments, and figure out where you are by whether or not you're seeing an integer in the data field. From what you've said it looks like the data breaks down pretty clearly:

First position is either an integer or a character (string? Is Thursday "Th"?). After that you have a variable number of non-integers until you get to the start time, then you have the end time, then building, then room. You're going to have to know this anyway (because Java is staticly/strongly typed), so might as well make use of it.

share|improve this answer
    
Thursday will be R, so a character will suffice. –  agent154 Jan 16 at 16:26

You could try processing the tokens from the back since these, according to yourself, have a consistent format. Then when you get on to the variable part you will have to make sure that the days of the week are valid, and if they're not assume it's the scheduling code. Of course, check that that's numeric too.

share|improve this answer

You might consider using Scanner rather than String and split(). It seems like using Scanner's various hasNext() and next() methods would allow you to set up logic to fit your needs and check if the next entry in the file is an integer or not, or matches a certain pattern such as hasNext("M"). Scanner's default delimeter is a whitespace character, so it should work fine for your input file, though you can also set the delimeter to any valid regex expression using useDelimeter().

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.