Commit 63fd74cd authored by Volker Krause's avatar Volker Krause
Browse files

Add an alternative way of decoding RCT2 reservation data

Some tickets diverge so far from the standard layout that all our recovery
attempts fail. We now also try a set of regular expression patterns on
the layouted text.

This makes MAV (Hungarian state railway) produced RCT2 tickets readable.
parent 455458e1
Pipeline #75704 passed with stage
in 10 minutes and 27 seconds
[
{
"@context": "http://schema.org",
"@type": "Rct2Ticket",
"coachNumber": "23",
"outboundArrivalStation": "MUENCHEN HBF",
"outboundArrivalTime": "2018-08-19T14:32:00",
"outboundClass": "2",
"outboundDepartureStation": "BUDAPEST-KELETI",
"outboundDepartureTime": "2018-08-19T07:40:00",
"passengerName": "Jőhn Á Doe",
"seatNumber": "101, 102",
"trainNumber": "RJX 42",
"type": "http://schema.org/TransportReservation"
}
]
U_TLAY010831RCT200410001011400015MÁV-START Zrt.0018011800018MENETJEGY+HELYJEGY0052011000012Jőhn Á Doe0118012300023FAHRSCHEIN+RESERVIERUNG0152010200002020155011400016ÜLŐHELY/SITZPL0201010800008CIV 1155060101050000519.08060701050000507:400613011500015BUDAPEST-KELETI0634011200012MUENCHEN HBF065201050000519.08065801050000514:32066801010000120703010100001*0709010100001*0713010100001*0734010100001*0754010100001*0760010100001*0768010100001*0801010300003ZUG0805010200002420811010300003RJX0815010500005WAGEN0821010200002230825010500005PLATZ0831010800008101, 1021201011500015START Europa DE1237010800008CARRIERS1301010200002011304011900020FELNŐTT/ERWACHSENER1401010200002011404011900020FELNŐTT/ERWACHSENER13370114000141155 1181 10801352010200003ÁR1358010300003HUF1362010900009*12345.001452010500005PREIS1458010300003EUR1462010900009***123.00
\ No newline at end of file
......@@ -10,6 +10,7 @@
#include <QDateTime>
#include <QDebug>
#include <QRegularExpression>
#include <cstring>
......@@ -22,6 +23,7 @@ class Rct2TicketPrivate : public QSharedData
public:
QDate firstDayOfValidity() const;
QDateTime parseTime(const QString &dateStr, const QString &timeStr) const;
QString reservationPatternCapture(QStringView name) const;
Uic9183TicketLayout layout;
QDateTime contextDt;
......@@ -67,6 +69,24 @@ QDateTime Rct2TicketPrivate::parseTime(const QString &dateStr, const QString &ti
return QDateTime({year, d.month(), d.day()}, t);
}
static constexpr const char* res_patterns[] = {
"ZUG +(?P<train_number>\\d+) +(?P<train_category>[A-Z][A-Z0-9]+) +WAGEN +(?P<coach>\\d+) +PLATZ +(?P<seat>\\d[\\d, ]+)"
};
QString Rct2TicketPrivate::reservationPatternCapture(QStringView name) const
{
const auto text = layout.text(8, 0, 72, 1);
for (const auto *pattern : res_patterns) {
QRegularExpression re{QLatin1String(pattern), QRegularExpression::CaseInsensitiveOption};
Q_ASSERT(re.isValid());
const auto match = re.match(text);
if (match.hasMatch()) {
return match.captured(name);
}
}
return {};
}
// 6x "U_TLAY"
// 2x version (always "01")
......@@ -186,8 +206,13 @@ QString Rct2Ticket::trainNumber() const
{
const auto t = type();
if (t == Reservation || t == TransportReservation || t == Upgrade) {
auto num = d->reservationPatternCapture(u"train_number");
if (!num.isEmpty()) {
return d->reservationPatternCapture(u"train_category") + QLatin1Char(' ') + num;
}
const auto cat = d->layout.text(8, 13, 3, 1).trimmed();
auto num = d->layout.text(8, 7, 5, 1).trimmed();
num = d->layout.text(8, 7, 5, 1).trimmed();
// check for train number bleeding into our left neighbour field (happens e.g. on ÖBB IRT/RES tickets)
if (num.isEmpty() || num.at(0).isDigit()) {
......@@ -214,7 +239,8 @@ QString Rct2Ticket::coachNumber() const
{
const auto t = type();
if (t == Reservation || t == TransportReservation) {
return d->layout.text(8, 26, 3, 1).trimmed();
const auto coach = d->reservationPatternCapture(u"coach");
return coach.isEmpty() ? d->layout.text(8, 26, 3, 1).trimmed() : coach;
}
return {};
}
......@@ -223,6 +249,11 @@ QString Rct2Ticket::seatNumber() const
{
const auto t = type();
if (t == Reservation || t == TransportReservation) {
const auto seat = d->reservationPatternCapture(u"seat");
if (!seat.isEmpty()) {
return seat;
}
const auto row8 = d->layout.text(8, 48, 23, 1).trimmed();
if (!row8.isEmpty()) {
return row8;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment