\n(.*?)", Pattern.DOTALL);
static final Pattern P_DEPARTURES_FINE = Pattern.compile("" //
+ "(\\d{1,2}:\\d{2}) | \n.*?" // plannedTime
+ "(?:\n" //
+ "(?: |(pünktlich|\\d{1,2}:\\d{2}))\n | \n" // predictedTime
+ ")?.*?" //
+ "
\\s*(.*?)\\s*\n" //
+ "" // destinationId
+ "\\s*(.*?)\\s*\n" // destination
+ ".*?" //
+ "(?:\n(" + ParserUtils.P_PLATFORM + ").*?)?" // position
, Pattern.DOTALL);
public QueryDeparturesResult queryDepartures(final String uri) throws IOException
{
// scrape page
final CharSequence page = ParserUtils.scrape(uri);
// parse page
final Matcher mHeadCoarse = P_DEPARTURES_HEAD_COARSE.matcher(page);
if (mHeadCoarse.matches())
{
// messages
if (mHeadCoarse.group(3) != null)
return new QueryDeparturesResult(uri, Status.NO_INFO);
else if (mHeadCoarse.group(4) != null)
return new QueryDeparturesResult(uri, Status.INVALID_STATION);
else if (mHeadCoarse.group(5) != null)
return new QueryDeparturesResult(uri, Status.SERVICE_DOWN);
final Matcher mHeadFine = P_DEPARTURES_HEAD_FINE.matcher(mHeadCoarse.group(1));
if (mHeadFine.matches())
{
final String location = ParserUtils.resolveEntities(mHeadFine.group(1));
final Date currentTime = ParserUtils.joinDateTime(ParserUtils.parseDate(mHeadFine.group(2)), ParserUtils
.parseTime(mHeadFine.group(3)));
final int stationId = Integer.parseInt(mHeadFine.group(4));
final List departures = new ArrayList(8);
String oldZebra = null;
final Matcher mDepCoarse = P_DEPARTURES_COARSE.matcher(mHeadCoarse.group(2));
while (mDepCoarse.find())
{
final String zebra = mDepCoarse.group(1);
if (oldZebra != null && zebra.equals(oldZebra))
throw new IllegalArgumentException("missed row? last:" + zebra);
else
oldZebra = zebra;
final Matcher mDepFine = P_DEPARTURES_FINE.matcher(mDepCoarse.group(2));
if (mDepFine.matches())
{
final Calendar current = new GregorianCalendar();
current.setTime(currentTime);
final Calendar parsed = new GregorianCalendar();
parsed.setTime(ParserUtils.parseTime(mDepFine.group(1)));
parsed.set(Calendar.YEAR, current.get(Calendar.YEAR));
parsed.set(Calendar.MONTH, current.get(Calendar.MONTH));
parsed.set(Calendar.DAY_OF_MONTH, current.get(Calendar.DAY_OF_MONTH));
if (ParserUtils.timeDiff(parsed.getTime(), currentTime) < -PARSER_DAY_ROLLOVER_THRESHOLD_MS)
parsed.add(Calendar.DAY_OF_MONTH, 1);
final Date plannedTime = parsed.getTime();
Date predictedTime = null;
final String prognosis = ParserUtils.resolveEntities(mDepFine.group(2));
if (prognosis != null)
{
if (prognosis.equals("pünktlich"))
predictedTime = plannedTime;
else
predictedTime = ParserUtils.joinDateTime(currentTime, ParserUtils.parseTime(prognosis));
}
final String lineType = mDepFine.group(3);
final String line = normalizeLine(lineType, ParserUtils.resolveEntities(mDepFine.group(4)));
final int destinationId = mDepFine.group(5) != null ? Integer.parseInt(mDepFine.group(5)) : 0;
final String destination = ParserUtils.resolveEntities(mDepFine.group(6));
final String position = mDepFine.group(7) != null ? "Gl. " + ParserUtils.resolveEntities(mDepFine.group(7)) : null;
final Departure dep = new Departure(plannedTime, predictedTime, line, line != null ? LINES.get(line.charAt(0)) : null, null,
position, destinationId, destination, null);
if (!departures.contains(dep))
departures.add(dep);
}
else
{
throw new IllegalArgumentException("cannot parse '" + mDepCoarse.group(2) + "' on " + uri);
}
}
return new QueryDeparturesResult(uri, stationId, location, currentTime, departures);
}
else
{
throw new IllegalArgumentException("cannot parse '" + mHeadCoarse.group(1) + "' on " + uri);
}
}
else
{
throw new IllegalArgumentException("cannot parse '" + page + "' on " + uri);
}
}
private static final Pattern P_NORMALIZE_LINE = Pattern.compile("([A-Za-zÄÖÜäöüßáàâéèêíìîóòôúùû]+)[\\s-]*(.*)");
private static String normalizeLine(final String type, final String line)
{
final Matcher m = P_NORMALIZE_LINE.matcher(line);
final String strippedLine = m.matches() ? m.group(1) + m.group(2) : line;
final char normalizedType = normalizeType(type);
if (normalizedType != 0)
return normalizedType + strippedLine;
throw new IllegalStateException("cannot normalize type " + type + " line " + line);
}
private static char normalizeType(final String type)
{
final String ucType = type.toUpperCase();
if (ucType.equals("OEC")) // ÖBB-EuroCity
return 'I';
if (ucType.equals("OIC")) // ÖBB-InterCity
return 'I';
if (ucType.equals("EC")) // EuroCity
return 'I';
if (ucType.equals("IC")) // InterCity
return 'I';
if (ucType.equals("ICE")) // InterCityExpress
return 'I';
if (ucType.equals("X")) // Interconnex
return 'I';
if (ucType.equals("EN")) // EuroNight
return 'I';
if (ucType.equals("CNL")) // CityNightLine
return 'I';
if (ucType.equals("DNZ")) // Berlin-Saratov, Berlin-Moskva
return 'I';
if (ucType.equals("INT")) // Rußland
return 'I';
if (ucType.equals("D")) // Rußland
return 'I';
if (ucType.equals("RR")) // Finnland
return 'I';
if (ucType.equals("TLK")) // Tanie Linie Kolejowe, Polen
return 'I';
if (ucType.equals("EE")) // Rumänien
return 'I';
if (ucType.equals("SC")) // SuperCity, Tschechien
return 'I';
if (ucType.equals("RJ")) // RailJet, Österreichische Bundesbahnen
return 'I';
if (ucType.equals("EST")) // Eurostar Frankreich
return 'I';
if (ucType.equals("ALS")) // Spanien
return 'I';
if (ucType.equals("ARC")) // Spanien
return 'I';
if (ucType.equals("TLG")) // Spanien, Madrid
return 'I';
if (ucType.equals("HOT")) // Spanien, Nacht
return 'I';
if (ucType.equals("AVE")) // Alta Velocidad Española, Spanien
return 'I';
if (ucType.equals("INZ")) // Schweden, Nacht
return 'I';
if (ucType.equals("OZ")) // Schweden, Oeresundzug
return 'I';
if (ucType.equals("X2")) // Schweden
return 'I';
if (ucType.equals("THA")) // Thalys
return 'I';
if (ucType.equals("TGV")) // Train à Grande Vitesse
return 'I';
if (ucType.equals("LYN")) // Dänemark
return 'I';
if (ucType.equals("ARZ")) // Frankreich, Nacht
return 'I';
if (ucType.equals("ES")) // Eurostar Italia
return 'I';
if (ucType.equals("ICN")) // Italien, Nacht
return 'I';
if (ucType.equals("UUU")) // Italien, Nacht
return 'I';
if (ucType.equals("RHI")) // ICE
return 'I';
if (ucType.equals("RHT")) // TGV
return 'I';
if (ucType.equals("TGD")) // TGV
return 'I';
if (ucType.equals("ECB")) // EC
return 'I';
if (ucType.equals("IRX")) // IC
return 'I';
if (ucType.equals("AIR"))
return 'I';
if (ucType.equals("R"))
return 'R';
if (ucType.equals("REX")) // RegionalExpress
return 'R';
if (ucType.equals("ZUG"))
return 'R';
if (ucType.equals("EZ")) // Erlebniszug
return 'R';
if (ucType.equals("S2")) // Helsinki-Turku
return 'R';
if (ucType.equals("RB")) // RegionalBahn
return 'R';
if (ucType.equals("RE"))
return 'R';
if (ucType.equals("DPN")) // TODO nicht evtl. doch eher ne S-Bahn?
return 'R';
if (ucType.equals("VIA"))
return 'R';
if (ucType.equals("PCC")) // Polen
return 'R';
if (ucType.equals("KM")) // Polen
return 'R';
if (ucType.equals("SKM")) // Polen
return 'R';
if (ucType.equals("SKW")) // Polen
return 'R';
if (ucType.equals("WKD")) // Warszawska Kolej Dojazdowa, Polen
return 'R';
if (ucType.equals("IR")) // Polen
return 'R';
if (ucType.equals("OS")) // Chop-Cierna nas Tisou
return 'R';
if (ucType.equals("SP")) // Polen
return 'R';
if (ucType.equals("EX")) // Polen
return 'R';
if (ucType.equals("E")) // Budapest, Ungarn
return 'R';
if (ucType.equals("IP")) // Ozd, Ungarn
return 'R';
if (ucType.equals("ZR")) // Bratislava, Slovakai
return 'R';
if (ucType.equals("CAT")) // Stockholm-Arlanda, Arlanda Express
return 'R';
if (ucType.equals("RT")) // Deutschland
return 'R';
if (ucType.equals("IRE")) // Interregio Express
return 'R';
if (ucType.equals("N")) // Frankreich, Tours
return 'R';
if (ucType.equals("DPF")) // VX=Vogtland Express
return 'R';
if (ucType.equals("S"))
return 'S';
if (ucType.equals("RSB")) // Schnellbahn Wien
return 'S';
if (ucType.equals("RER")) // Réseau Express Régional, Frankreich
return 'S';
if (ucType.equals("U"))
return 'U';
if (ucType.equals("STR"))
return 'T';
if (ucType.equals("LKB"))
return 'T';
if (ucType.equals("BUS"))
return 'B';
if (ucType.equals("RFB"))
return 'B';
if (ucType.equals("OBU"))
return 'B';
if (ucType.equals("AST"))
return 'B';
if (ucType.equals("ICB")) // ICBus
return 'B';
if (ucType.equals("FB")) // Polen
return 'B';
if (ucType.equals("BSV")) // Deutschland
return 'B';
if (ucType.equals("LT")) // Linien-Taxi
return 'B';
if (ucType.equals("SCH"))
return 'F';
if (ucType.equals("AS")) // SyltShuttle
return 'F';
if (ucType.equals("SB"))
return 'C';
if (ucType.equals("LIF"))
return 'C';
if (ucType.equals("U70")) // U.K.
return '?';
if (ucType.equals("R84"))
return '?';
if (ucType.equals("S84"))
return '?';
if (ucType.equals("T84"))
return '?';
return 0;
}
private static final Map LINES = new HashMap();
static
{
LINES.put('I', new int[] { Color.WHITE, Color.RED, Color.RED });
LINES.put('R', new int[] { Color.GRAY, Color.WHITE });
LINES.put('S', new int[] { Color.parseColor("#006e34"), Color.WHITE });
LINES.put('U', new int[] { Color.parseColor("#003090"), Color.WHITE });
LINES.put('T', new int[] { Color.parseColor("#cc0000"), Color.WHITE });
LINES.put('B', new int[] { Color.parseColor("#993399"), Color.WHITE });
LINES.put('F', new int[] { Color.BLUE, Color.WHITE });
LINES.put('?', new int[] { Color.DKGRAY, Color.WHITE });
}
public int[] lineColors(final String line)
{
return LINES.get(line.charAt(0));
}
}
|